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.