Spring 表达式语言 (SpEL)
您可以使用 Spring 表达式语言 编写的表达式来配置许多 Spring Integration 组件。
在大多数情况下,#root 对象是 Message,它有两个属性(headers 和 payload),允许使用诸如 payload、payload.thing、headers['my.header'] 等表达式。
在某些情况下,还会提供额外的变量。例如,<int-http:inbound-gateway/> 提供了 #requestParams(来自 HTTP 请求的参数)和 #pathVariables(来自 URI 中路径占位符的值)。
对于所有 SpEL 表达式,BeanResolver 可用于引用应用程序上下文中的任何 bean,例如 @myBean.foo(payload)。此外,还提供了两个 PropertyAccessor。MapAccessor 允许通过键访问 Map 中的值,而 ReflectivePropertyAccessor 允许访问字段和符合 JavaBean 规范的属性(通过 getter 和 setter)。这就是您访问 Message 头和 payload 属性的方式。
SpEL 评估上下文自定义
从 Spring Integration 3.0 开始,您可以向框架使用的 SpEL 评估上下文添加额外的 PropertyAccessor 实例。框架提供了(只读)JacksonPropertyAccessor,您可以使用它访问 JsonNode 或 String 中的 JSON 字段。如果您有特定需求,也可以创建自己的 PropertyAccessor。
提供了 JacksonIndexAccessor 实现,该实现知道如何使用 Jackson 的 ArrayNode API 从 JSON 数组中读取索引。支持以整数文字形式提供的索引,例如 myJsonArray[1]。还支持负索引,例如 myJsonArray[-1],它等同于 myJsonArray[myJsonArray.length - 1]。此外,对于任何超出范围的索引,都返回 null(有关详细信息,请参阅 ArrayNode.get(int))。
此外,您可以添加自定义函数。自定义函数是在类上声明的 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>
从 6.4 版本开始,AbstractEvaluationContextFactoryBean 支持注入 IndexAccessor 实例。有关更多信息,请参阅 AbstractEvaluationContextFactoryBean 方法的 Javadoc。
为了方便起见,Spring Integration 为属性访问器和函数都提供了命名空间支持,如下文所述。框架会为您自动配置工厂 bean。
此工厂 bean 定义会覆盖默认的 integrationEvaluationContext bean 定义。它将自定义访问器和一个自定义函数添加到列表中,该列表还包括前面提到的标准访问器。
请注意,自定义函数是静态方法。在上面的示例中,自定义函数是一个名为 MyFunctions 的类上的静态方法 calc,它接受一个类型为 MyThing 的单个参数。
假设您有一个 payload 类型为 MyThing 的 Message。进一步假设您需要执行一些操作,从 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 函数
Spring Integration 提供了命名空间支持,允许您创建 SpEL 自定义函数。您可以指定 <spel-function/> 组件,以便为整个框架使用的 EvaluationContext 提供自定义 SpEL 函数。您无需配置前面所示的工厂 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)" />
鉴于前面的例子
-
ID 为
integrationEvaluationContext的默认IntegrationEvaluationContextFactoryBeanbean 已注册到应用程序上下文。 -
<spel-function/>被解析并添加到integrationEvaluationContext的functionsMap中,作为以其id为键、静态Method为值的 Map 条目。 -
integrationEvaluationContext工厂 bean 创建一个新的StandardEvaluationContext实例,并使用默认的PropertyAccessor实例、BeanResolver和自定义函数进行配置。 -
该
EvaluationContext实例被注入到ExpressionEvaluatingTransformerbean 中。
要通过 Java 配置提供 SpEL 函数,您可以为每个函数声明一个 SpelFunctionFactoryBean bean。以下示例显示了如何创建自定义函数
@Bean
public SpelFunctionFactoryBean xpath() {
return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate");
}
在父上下文中声明的 SpEL 函数在任何子上下文中也可用。每个上下文都有自己的 integrationEvaluationContext 工厂 bean 实例,因为每个上下文都需要不同的 BeanResolver,但函数声明是继承的,可以通过声明同名的 SpEL 函数来覆盖。 |
内置 SpEL 函数
Spring Integration 提供以下标准函数,它们在启动时会自动注册到应用程序上下文
-
#jsonPath:评估指定对象上的“jsonPath”。此函数调用JsonPathUtils.evaluate(…),它委托给 Jayway JsonPath 库。以下列表显示了一些使用示例<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还支持第三个(可选)参数:一个com.jayway.jsonpath.Filter数组,可以通过引用 bean 或 bean 方法(例如)提供。使用此功能需要 Jayway JsonPath 库( json-path.jar)位于类路径中。否则,#jsonPathSpEL 函数将不会注册。有关 JSON 的更多信息,请参阅 Transformer 中的“JSON 转换器”。
-
#xpath:用于评估给定对象上的 xpath。有关 XML 和 XPath 的更多信息,请参阅 XML 支持 - 处理 XML Payload。
属性访问器
Spring Integration 提供了命名空间支持,允许您创建 SpEL 自定义 PropertyAccessor 实现。您可以使用 <spel-property-accessors/> 组件向整个框架使用的 EvaluationContext 提供自定义 PropertyAccessor 实例列表。无需配置前面所示的工厂 bean,您可以添加此组件,框架会自动将访问器添加到默认的 integrationEvaluationContext 工厂 bean。此外,从 6.4 版本开始,提供了一个专门的 <index-accessors> 子元素来以类似方式配置 IndexAccessor bean。以下示例显示了如何操作
<int:spel-property-accessors>
<index-accessors>
<beans:bean id="jsonIndex" class="org.springframework.integration.json.JacksonIndexAccessor"/>
</index-accessors>
<bean id="jsonPA" class="org.springframework.integration.json.JacksonPropertyAccessor"/>
<ref bean="fooPropertyAccessor"/>
</int:spel-property-accessors>
在前面的示例中,两个自定义 PropertyAccessor 实例被注入到 EvaluationContext 中(按照它们声明的顺序)。
要通过 Java 配置提供 PropertyAccessor 实例,您应该声明一个名为 spelPropertyAccessorRegistrar 的 SpelPropertyAccessorRegistrar bean(由 IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME 常量指定)。以下示例显示了如何使用 Java 配置两个自定义 PropertyAccessor(从 6.4 版本开始还包括 IndexAccessor)实例
@Bean
public SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() {
return new SpelPropertyAccessorRegistrar(new JacksonPropertyAccessor())
.add(fooPropertyAccessor())
.add(new JacksonIndexAccessor());
}
|
在父上下文中声明的自定义
|