Spring Expression Language (SpEL)

您可以使用以 Spring Expression Language 编写的表达式来配置许多 Spring Integration 组件。 在大多数情况下,#root 对象是 Message,它具有两个属性(headerspayload),允许使用类似于 payloadpayload.thingheaders['my.header'] 等表达式的表达式。 在某些情况下会提供附加变量。例如,<int-http:inbound-gateway/> 提供 #requestParams(来自 HTTP 请求的参数)和 #pathVariables(URI 中路径占位符中的值)。 对于所有 SpEL 表达式,BeanResolver 都可用于启用对应用程序上下文中任何 bean 的引用(例如,@myBean.foo(payload))。此外,还可以使用两个 PropertyAccessorsMapAccessor 可以使用键来访问 Map 中的值,而 ReflectivePropertyAccessor 则允许访问字段和 JavaBean 兼容属性(通过使用 getter 和 setter)。以下是访问 Message 标头和 payload 属性的方式。

SpEL Evaluation Context Customization

从 Spring Integration 3.0 开始,您可以将附加的 PropertyAccessor 实例添加到框架使用的 SpEL 求值上下文中。该框架提供了(只读)JsonPropertyAccessor,您可以使用它来访问 JsonNodeString 中的字段。您还可以在有特定需求时创建自己的 PropertyAccessor

此外,您还可以添加自定义函数。自定义函数是声明在一个类上的 static 方法。函数和属性访问器在整个框架中使用的任何 SpEL 表达式中都可用。

以下配置显示了如何使用自定义属性访问器和函数直接配置 IntegrationEvaluationContextFactoryBean

<bean id="integrationEvaluationContext"
			class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
	<property name="propertyAccessors">
		<util:map>
			<entry key="things">
				<bean class="things.MyCustomPropertyAccessor"/>
			</entry>
		</util:map>
	</property>
	<property name="functions">
		<map>
			<entry key="barcalc" value="#{T(things.MyFunctions).getMethod('calc', T(things.MyThing))}"/>
		</map>
	</property>
</bean>

为了方便起见,Spring Integration 为属性访问器和函数提供命名空间支持,如以下部分中所述。该框架会自动为您配置工厂 bean。

此工厂 Bean 定义将覆盖默认的“@44”Bean 定义。它将在列表中添加自定义访问器和一个自定义函数(包括标准访问器“@45”)。

请注意,自定义函数是静态方法。在前面的示例中,自定义函数是一个名为 calc 的静态方法,位于名为 MyFunctions 的类上,并接受一个类型为 MyThing 的参数。

假设您有一个 payload 类型为 MyThingMessage。此外,假设您需要执行一些操作来从 MyThing 创建一个名为 MyObject 的对象,然后调用该对象上的一个名为 calc 的自定义函数。

标准属性访问器不知道如何从 MyThing 中获取 MyObject,因此您可以编写并配置一个自定义属性访问器来执行此操作。因此,您的最终表达式可能是 "#barcalc(payload.myObject)"

工厂 bean 有另一个属性 (typeLocator),它允许您自定义在 SpEL 求值期间使用的 TypeLocator。您可能需要在使用非标准 ClassLoader 的某些环境中运行时进行此操作。在以下示例中,SpEL 表达式始终使用 bean 工厂的类加载器:

<bean id="integrationEvaluationContext"
		class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
	<property name="typeLocator">
		<bean class="org.springframework.expression.spel.support.StandardTypeLocator">
			<constructor-arg value="#{beanFactory.beanClassLoader}"/>
		</bean>
	</property>
</bean>

SpEL Functions

Spring Integration 提供命名空间支持,以便你可以创建 SpEL 自定义函数。你可以指定 <spel-function/> 组件,以便向整个框架中使用的 EvaluationContext 提供 custom SpEL functions 。你可以添加一个或多个此类组件,而不是配置之前所示的工厂 bean,且框架会自动将它们添加到默认 integrationEvaluationContext 工厂 bean 中。

例如,假设您有一个有用的静态方法来评估 XPath。以下示例显示了如何创建一个自定义函数来使用该方法:

<int:spel-function id="xpath"
	class="com.something.test.XPathUtils" method="evaluate(java.lang.String, java.lang.Object)"/>

<int:transformer input-channel="in" output-channel="out"
		 expression="#xpath('//things/@mythings', payload)" />

给定前面的示例:

  • 默认 “IntegrationEvaluationContextFactoryBean” bean(ID 为 “integrationEvaluationContext”)将使用应用程序上下文注册。

  • 解析 “&lt;spel-function/&gt;” 并在作为映射输入项,并将它的 “id” 作为键,静态 “Method” 作为值,添加到 “functions” “Map” 的 “integrationEvaluationContext” 中。

  • integrationEvaluationContext” 工厂 Bean 创建一个新的 “StandardEvaluationContext” 实例,使用默认 “PropertyAccessor” 实例、“BeanResolver” 和自定义函数对其进行配置。

  • 该 “EvaluationContext” 将注入到 “ExpressionEvaluatingTransformer” bean 中。

要使用 Java 配置提供 SpEL 函数,您可以为每个函数声明一个 SpelFunctionFactoryBean bean。以下示例显示了如何创建一个自定义函数:

@Bean
public SpelFunctionFactoryBean xpath() {
    return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate");
}

在父上下文中声明的 SpEL 函数也可在任何子上下文中使用。每个上下文都有其自己的 integrationEvaluationContext 工厂 Bean 实例,因为每个上下文需要不同的 BeanResolver,但函数声明会继承,并且可以通过声明具有相同名称的 SpEL 函数来覆盖它们。

Built-in SpEL Functions

Spring Integration 提供了以下标准函数,这些函数会在启动时自动注册到应用程序上下文中:

  • #jsonPath”:在指定对象上评估一个 “jsonPath”。此函数调用 “JsonPathUtils.evaluate(&#8230;&#8203;)”,它委托给 “ Jayway JsonPath library”。以下清单显示一些用法示例:[source, xml]

<transformer expression="#jsonPath(payload, '$.store.book[0].author')"/>

<filter expression="#jsonPath(payload,'$..book[2].isbn') matches '\d-\d{3}-\d{5}-\d'"/>

<splitter expression="#jsonPath(payload, '$.store.book')"/>

<router expression="#jsonPath(payload, headers.jsonPath)">
	<mapping channel="output1" value="reference"/>
	<mapping channel="output2" value="fiction"/>
</router>

#jsonPath 还支持第三个(可选)参数:由对 bean 或 bean 方法(例如)引用提供的 com.jayway.jsonpath.Filter 数组。

使用此函数需要类路径上有 Jayway JsonPath 库 (json-path.jar)。否则不会注册 #jsonPath SpEL 函数。

有关 JSON 的更多信息,请参阅 Transformer 中的“JSON Transformer”, * “#xpath”:在提供的对象上评估一个 xpath。有关 XML 和 XPath 的详细信息,请参阅 “XML Support - Dealing with XML Payloads”。

Property Accessors

Spring Integration 提供命名空间支持,以便你可以创建 SpEL 自定义 PropertyAccessor 实现。你可以使用 <spel-property-accessors/> 组件,以便向整个框架中使用的 EvaluationContext 提供自定义 PropertyAccessor 实例列表。你可以添加一个或多个此类组件,而不是配置之前所示的工厂 bean,且框架会自动将访问器添加到默认 integrationEvaluationContext 工厂 bean 中。以下示例演示如何执行此操作:

<int:spel-property-accessors>
	<bean id="jsonPA" class="org.springframework.integration.json.JsonPropertyAccessor"/>
	<ref bean="fooPropertyAccessor"/>
</int:spel-property-accessors>

在前面的示例中,将两个自定义 PropertyAccessor 实例注入到 EvaluationContext 中(按声明的顺序)。

要使用 Java 配置来提供 PropertyAccessor 实例,你应声明一个 SpelPropertyAccessorRegistrar Bean,名称为 spelPropertyAccessorRegistrar(由 IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME 常量决定)。以下示例展示了如何使用 Java 配置两个自定义 PropertyAccessor 实例:

@Bean
public SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() {
    return new SpelPropertyAccessorRegistrar(new JsonPropertyAccessor())
                    .add(fooPropertyAccessor());
}

在父上下文中声明的自定义 PropertyAccessor 实例在任何子上下文中也可以用。它们放在结果列表的末尾(但在默认 org.springframework.context.expression.MapAccessoro.s.expression.spel.support.ReflectivePropertyAccessor 之前)。如果你在子上下文中使用同一 Bean ID 声明 PropertyAccessor,它将覆盖父访问器。<spel-property-accessors/> 中声明的 Bean 必须具有一个“ID”属性。最终的使用顺序如下:

  • 当前上下文中访问器的声明顺序

  • 来自父上下文的任何访问器,顺序

  • The MapAccessor

  • The ReflectivePropertyAccessor