Spring Expression Language (SpEL)

您可以使用以 Spring Expression Language 编写的表达式来配置许多 Spring Integration 组件。

You can configure many Spring Integration components by using expressions written in the Spring Expression Language.

在大多数情况下,#root 对象是 Message,它具有两个属性(headerspayload),允许使用类似于 payloadpayload.thingheaders['my.header'] 等表达式的表达式。

In most cases, the #root object is the Message, which has two properties (headers and payload) that allow such expressions as payload, payload.thing, headers['my.header'], and so on.

在某些情况下会提供附加变量。例如,<int-http:inbound-gateway/> 提供 #requestParams(来自 HTTP 请求的参数)和 #pathVariables(URI 中路径占位符中的值)。

In some cases, additional variables are provided. For example, <int-http:inbound-gateway/> provides #requestParams (parameters from the HTTP request) and #pathVariables (values from path placeholders in the URI).

对于所有 SpEL 表达式,BeanResolver 都可用于启用对应用程序上下文中任何 bean 的引用(例如,@myBean.foo(payload))。此外,还可以使用两个 PropertyAccessorsMapAccessor 可以使用键来访问 Map 中的值,而 ReflectivePropertyAccessor 则允许访问字段和 JavaBean 兼容属性(通过使用 getter 和 setter)。以下是访问 Message 标头和 payload 属性的方式。

For all SpEL expressions, a BeanResolver is available to enable references to any bean in the application context (for example, @myBean.foo(payload)). In addition, two PropertyAccessors are available. A MapAccessor enables accessing values in a Map by using a key and a ReflectivePropertyAccessor, which allows access to fields and JavaBean compliant properties (by using getters and setters). This is how you can access the Message headers and payload properties.

SpEL Evaluation Context Customization

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

Starting with Spring Integration 3.0, you can add additional PropertyAccessor instances to the SpEL evaluation contexts used by the framework. The framework provides the (read-only) JsonPropertyAccessor, which you can use to access fields from a JsonNode or JSON in a String. You can also create your own PropertyAccessor if you have specific needs.

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

In addition, you can add custom functions. Custom functions are static methods declared on a class. Functions and property accessors are available in any SpEL expression used throughout the framework.

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

The following configuration shows how to directly configure the IntegrationEvaluationContextFactoryBean with custom property accessors and functions:

<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。

For convenience, Spring Integration provides namespace support for both property accessors and functions, as described in the following sections. The framework automatically configures the factory bean on your behalf.

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

This factory bean definition overrides the default integrationEvaluationContext bean definition. It adds the custom accessor and one custom function to the list (which also includes the standard accessors mentioned earlier).

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

Note that custom functions are static methods. In the preceding example, the custom function is a static method called calc on a class called MyFunctions and takes a single parameter of type MyThing.

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

Suppose you have a Message with a payload that has a type of MyThing. Further, suppose that you need to perform some action to create an object called MyObject from MyThing and then invoke a custom function called calc on that object.

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

The standard property accessors do not know how to get a MyObject from a MyThing, so you could write and configure a custom property accessor to do so. As a result, your final expression might be "#barcalc(payload.myObject)".

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

The factory bean has another property (typeLocator), which lets you customize the TypeLocator used during SpEL evaluation. You might need to do so running in some environments that use a non-standard ClassLoader. In the following example, SpEL expressions always use the bean factory’s class loader:

<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 中。

Spring Integration provides namespace support to let you create SpEL custom functions. You can specify <spel-function/> components to provide custom SpEL functions to the EvaluationContext used throughout the framework. Instead of configuring the factory bean shown earlier, you can add one or more of these components, and the framework automatically adds them to the default integrationEvaluationContext factory bean.

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

For example, suppose you have a useful static method to evaluate XPath. The following example shows how you can create a custom function to use that method:

<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)" />

给定前面的示例:

Given the preceding example:

  • The default IntegrationEvaluationContextFactoryBean bean with an ID of integrationEvaluationContext is registered with the application context.

  • The <spel-function/> is parsed and added to the functions Map of integrationEvaluationContext as a map entry with its id as the key and the static Method as the value.

  • The integrationEvaluationContext factory bean creates a new StandardEvaluationContext instance, and it is configured with the default PropertyAccessor instances, a BeanResolver, and the custom functions.

  • That EvaluationContext instance is injected into the ExpressionEvaluatingTransformer bean.

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

To provide a SpEL Function by using Java configuration, you can declare a SpelFunctionFactoryBean bean for each function. The following example shows how to create a custom function:

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

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

SpEL functions declared in a parent context are also made available in any child contexts. Each context has its own instance of the integrationEvaluationContext factory bean, because each needs a different BeanResolver, but the function declarations are inherited and can be overridden by declaring a SpEL function with the same name.

Built-in SpEL Functions

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

Spring Integration provides the folloiwng standard functions, which are registered with the application context automatically on start up:

  • #jsonPath: Evaluates a 'jsonPath' on a specified object. This function invokes JsonPathUtils.evaluate(…​), which delegates to the Jayway JsonPath library. The following listing shows some usage examples:[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 数组。

#jsonPath also supports a third (optional) parameter: an array of com.jayway.jsonpath.Filter, which can be provided by a reference to a bean or bean method (for example).

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

Using this function requires the Jayway JsonPath library (json-path.jar) to be on the classpath. Otherwise, the #jsonPath SpEL function is not registered.

有关 JSON 的更多信息,请参阅 Transformer 中的“JSON Transformer”,

For more information regarding JSON see 'JSON Transformers' in Transformer. * #xpath: To evaluate an xpath on some provided object. For more information regarding XML and XPath, see XML Support - Dealing with XML Payloads.

Property Accessors

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

Spring Integration provides namespace support to let you create SpEL custom PropertyAccessor implementations. You can use the <spel-property-accessors/> component to provide a list of custom PropertyAccessor instances to the EvaluationContext used throughout the framework. Instead of configuring the factory bean shown earlier, you can add one or more of these components, and the framework automatically adds the accessors to the default integrationEvaluationContext factory bean. The following example shows how to do so:

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

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

In the preceding example, two custom PropertyAccessor instances are injected into the EvaluationContext (in the order in which they are declared).

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

To provide PropertyAccessor instances by using Java Configuration, you should declare a SpelPropertyAccessorRegistrar bean with a name of spelPropertyAccessorRegistrar (dictated by the IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME constant). The following example shows how to configure two custom PropertyAccessor instances with Java:

@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”属性。最终的使用顺序如下:

Custom PropertyAccessor instances declared in a parent context are also made available in any child contexts. They are placed at the end of result list (but before the default org.springframework.context.expression.MapAccessor and o.s.expression.spel.support.ReflectivePropertyAccessor). If you declare a PropertyAccessor with the same bean ID in a child context, it overrides the parent accessor. Beans declared within a <spel-property-accessors/> must have an 'id' attribute. The final order of usage is as follows:

  • The accessors in the current context, in the order in which they are declared

  • Any accessors from parent contexts, in order

  • The MapAccessor

  • The ReflectivePropertyAccessor