Spring 表达式语言 (SpEL)

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

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

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

对于所有 SpEL 表达式,BeanResolver 可用于引用应用程序上下文中的任何 bean,例如 @myBean.foo(payload)。此外,还提供了两个 PropertyAccessorMapAccessor 允许通过键访问 Map 中的值,而 ReflectivePropertyAccessor 允许访问字段和符合 JavaBean 规范的属性(通过 getter 和 setter)。这就是您访问 Message 头和 payload 属性的方式。

SpEL 评估上下文自定义

从 Spring Integration 3.0 开始,您可以向框架使用的 SpEL 评估上下文添加额外的 PropertyAccessor 实例。框架提供了(只读)JacksonPropertyAccessor,您可以使用它访问 JsonNodeString 中的 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 类型为 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 函数

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 的默认 IntegrationEvaluationContextFactoryBean bean 已注册到应用程序上下文。

  • <spel-function/> 被解析并添加到 integrationEvaluationContextfunctions Map 中,作为以其 id 为键、静态 Method 为值的 Map 条目。

  • 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 函数来覆盖。

内置 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)位于类路径中。否则,#jsonPath SpEL 函数将不会注册。

    有关 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 实例,您应该声明一个名为 spelPropertyAccessorRegistrarSpelPropertyAccessorRegistrar 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());
}

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

  • 当前上下文中的访问器,按声明顺序排列

  • 父上下文中的任何访问器,按顺序排列

  • MapAccessor

  • ReflectivePropertyAccessor

© . This site is unofficial and not affiliated with VMware.