Spring 表示式語言 (SpEL)
可以使用 Spring 表示式語言 編寫的表示式來配置許多 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)
)。此外,還提供了兩個 PropertyAccessor
。MapAccessor
允許使用 key 訪問 Map
中的值,而 ReflectivePropertyAccessor
允許訪問欄位和符合 JavaBean 規範的屬性(透過 getter 和 setter)。這就是訪問 Message
頭部和載荷屬性的方式。
SpEL 求值上下文定製
從 Spring Integration 3.0 開始,你可以向框架使用的 SpEL 求值上下文新增額外的 PropertyAccessor
例項。框架提供了(只讀的)JsonPropertyAccessor
,你可以用它來訪問 JsonNode
或字串形式的 JSON 中的欄位。如果你的需求特殊,也可以建立自己的 PropertyAccessor
。
從 6.4 版本開始,提供了 JsonIndexAccessor
實現,它知道如何使用 Jackson 的 ArrayNode
API 從 JSON 陣列中讀取索引。支援以整數文字形式提供的索引,例如 myJsonArray[1]
。也支援負數索引,例如 myJsonArray[-1]
等同於 myJsonArray[myJsonArray.length - 1]
。此外,對於任何超出範圍的索引,將返回 null
(詳情請參閱 ArrayNode.get(int)
)。
此外,你還可以新增自定義函式。自定義函式是類中宣告的靜態方法。在整個框架中使用的任何 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 為屬性訪問器和函式提供了名稱空間支援,如下一節所述。框架會自動為你配置 factory bean。
這個 factory bean 定義會覆蓋預設的 integrationEvaluationContext
bean 定義。它將自定義訪問器和一個自定義函式新增到列表中(該列表也包含前面提到的標準訪問器)。
請注意,自定義函式是靜態方法。在前面的例子中,自定義函式是 MyFunctions
類中名為 calc
的靜態方法,它接受一個 MyThing
型別的引數。
假設你有一個 Message
,其載荷型別為 MyThing
。進一步假設你需要執行一些操作從 MyThing
建立一個名為 MyObject
的物件,然後在該物件上呼叫名為 calc
的自定義函式。
標準屬性訪問器不知道如何從 MyThing
獲取 MyObject
,因此你可以編寫並配置一個自定義屬性訪問器來實現。這樣,你的最終表示式可能就是 "#barcalc(payload.myObject)"
。
該 factory bean 還有另一個屬性(typeLocator
),允許你定製 SpEL 求值期間使用的 TypeLocator
。在某些使用非標準 ClassLoader
的環境中執行時,你可能需要這樣做。在以下示例中,SpEL 表示式總是使用 bean factory 的類載入器
<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 函式。你可以新增一個或多個此類元件,而不是像前面那樣配置 factory bean,框架會自動將它們新增到預設的 integrationEvaluationContext
factory 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/>
會被解析,並作為 map entry 新增到integrationEvaluationContext
的functions
Map 中,其id
作為 key,靜態Method
作為 value。 -
integrationEvaluationContext
factory bean 建立一個新的StandardEvaluationContext
例項,並配置了預設的PropertyAccessor
例項、一個BeanResolver
和自定義函式。 -
該
EvaluationContext
例項會被注入到ExpressionEvaluatingTransformer
bean 中。
要使用 Java 配置提供 SpEL 函式,你可以為每個函式宣告一個 SpelFunctionFactoryBean
bean。以下示例展示瞭如何建立一個自定義函式
@Bean
public SpelFunctionFactoryBean xpath() {
return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate");
}
在父上下文中宣告的 SpEL 函式在任何子上下文中也可用。每個上下文都有自己的 integrationEvaluationContext factory 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 方法(例如)來提供。使用此函式需要 classpath 中包含 Jayway JsonPath 庫( json-path.jar
)。否則,#jsonPath
SpEL 函式將不會註冊。有關 JSON 的更多資訊,請參閱 轉換器 中的 'JSON 轉換器'。
-
#xpath
:在提供的物件上求值 xpath。有關 XML 和 XPath 的更多資訊,請參閱 XML 支援 - 處理 XML 載荷。
屬性訪問器
Spring Integration 提供了名稱空間支援,允許你建立 SpEL 自定義 PropertyAccessor
實現。你可以使用 <spel-property-accessors/>
元件,為整個框架中使用的 EvaluationContext
提供自定義 PropertyAccessor
例項列表。你可以新增此元件,而不是像前面那樣配置 factory bean,框架會自動將訪問器新增到預設的 integrationEvaluationContext
factory bean 中。此外,從 6.4 版本開始,提供了一個專門的 <index-accessors>
子元素,以類似方式配置 IndexAccessor
bean。以下示例展示瞭如何實現
<int:spel-property-accessors>
<index-accessors>
<beans:bean id="jsonIndex" class="org.springframework.integration.json.JsonIndexAccessor"/>
</index-accessors>
<bean id="jsonPA" class="org.springframework.integration.json.JsonPropertyAccessor"/>
<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 JsonPropertyAccessor())
.add(fooPropertyAccessor())
.add(new JsonIndexAccessor());
}
在父上下文中宣告的自定義
|