# Spring 表达式语言
# Spring 表达式语言
你可以通过使用Spring Expression Language (opens new window)中编写的表达式来配置许多 Spring 集成组件。
在大多数情况下,#root
对象是Message
,它有两个属性(headers
和payload
),允许这样的表达式,如payload
,payload.thing
,headers['my.header']
,以此类推。
在某些情况下,提供了额外的变量。例如,<int-http:inbound-gateway/>
提供#requestParams
(来自 HTTP 请求的参数)和#pathVariables
(来自 URI 中的路径占位符的值)。
对于所有 SPEL 表达式,可以使用BeanResolver
来启用对应用程序上下文中的任何 Bean 的引用(例如,@myBean.foo(payload)
)。此外,还有两个PropertyAccessors
可用。MapAccessor
允许通过使用一个键和ReflectivePropertyAccessor
访问Map
中的值,这允许访问字段和 JavaBean 兼容的属性(通过使用 getter 和 setter)。这就是访问Message
标头和有效负载属性的方法。
# spel 评估上下文定制
从 Spring Integration3.0 开始,你可以向框架使用的 SPEL 评估上下文添加额外的PropertyAccessor
实例。该框架提供(只读)JsonPropertyAccessor
,你可以使用它从JsonNode
或String
中的 JSON 访问字段。如果你有特定的需求,也可以创建自己的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 为了方便起见,集成为属性访问器和函数提供了名称空间支持,如下文所述。该框架自动为你配置工厂 Bean。
这个工厂 Bean 定义覆盖了默认的integrationEvaluationContext
Bean 定义。它将自定义访问器和一个自定义函数添加到列表中(其中还包括标准访问器前面提到过)。
请注意,自定义函数是静态方法。在前面的示例中,自定义函数是在一个名为MyFunctions
的类上的一个名为calc
的静态方法,并接受类型为MyThing
的单个参数。
假设你有一个Message
,其有效负载的类型为MyThing
。进一步假设你需要执行一些操作来从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 集成提供了名称空间支持,以允许你创建 SPEL 自定义函数。你可以指定<spel-function/>
组件来为整个框架中使用的自定义 SPEL 函数 (opens new window)提供EvaluationContext
。你可以添加一个或多个这些组件,而不是配置前面所示的工厂 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/>
解析并添加到functions
的Map
中,作为一个映射条目,其id
作为键,而静态Method
作为值。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 集成提供了 FolloiWNG 标准功能,这些功能在启动时自动注册到应用程序上下文中:
#jsonPath
:在指定的对象上计算“jsonpath”。这个函数调用JsonPathUtils.evaluate(…)
,将其委托给Jayway JsonPath 库 (opens new window)。下面的清单展示了一些使用示例:<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
](https://github.com/json-path/jsonpath#filter-predicates)的数组,它可以通过引用 Bean 或 Bean 方法(例如)来提供。使用此函数需要 Jayway JsonPath 库( json-path.jar
)位于 Classpath 上。
否则将不注册#jsonPath
spel 函数。有关 JSON 的更多信息,请参见变压器中的“JSON Transformers”。
#xpath
:在某些提供的对象上计算“XPath”。有关 XML 和 XPath 的更多信息,请参见XML 支持-处理 XML 有效负载。
# 属性访问器
Spring 集成提供了名称空间支持,以允许你创建 SPEL 自定义[PropertyAccessor
](https://DOCS. Spring.io/ Spring/DOCS/current/javadoc-api/org/springframework/expression/propertyaccessor.html)实现。你可以使用<spel-property-accessors/>
组件为整个框架中使用的PropertyAccessor
实例提供自定义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.MapAccessor 之前)并且o.s.expression.spel.support.ReflectivePropertyAccessor )。如果在子上下文中声明一个具有相同 Bean ID 的 PropertyAccessor ,则它将覆盖父访问器。在 <spel-property-accessors/> 中声明的 bean 必须具有一个“id”属性。使用的最终顺序如下: 当前上下文中的访问者,按照它们被声明为 * 来自父上下文的任何访问器的顺序,按照 MapAccessor 的顺序 |
---|