Spring 式言語 (SpEL)

Spring 式言語で記述された式を使用して、多くの Spring Integration コンポーネントを構成できます。

ほとんどの場合、#root オブジェクトは Message であり、payloadpayload.thingheaders['my.header'] などの式を許可する 2 つのプロパティ(headers および payload)があります。

場合によっては、追加の変数が提供されます。例: <int-http:inbound-gateway/> は、#requestParams (HTTP リクエストからのパラメーター)および #pathVariables (URI のパスプレースホルダーからの値)を提供します。

すべての SpEL 式について、BeanResolver を使用して、アプリケーションコンテキスト内の Bean への参照を有効にすることができます(例: @myBean.foo(payload))。さらに、2 つの PropertyAccessors が利用可能です。MapAccessor は、キーと ReflectivePropertyAccessor を使用して Map の値にアクセスできるようにします。これにより、フィールドおよび JavaBean 準拠のプロパティにアクセスできます(getter および setter を使用)。これにより、Message ヘッダーとペイロードプロパティにアクセスできます。

SpEL 評価コンテキストのカスタマイズ

Spring Integration 3.0 以降、フレームワークが使用する SpEL 評価コンテキストに追加の PropertyAccessor インスタンスを追加できます。フレームワークは(読み取り専用) JsonPropertyAccessor を提供します。これを使用して、String の JsonNode または 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 Integration は、次のセクションで説明するように、プロパティアクセサーと関数の両方に名前空間のサポートを提供します。フレームワークは、ユーザーに代わってファクトリ Bean を自動的に構成します。

このファクトリ Bean 定義は、デフォルトの integrationEvaluationContext Bean 定義をオーバーライドします。カスタムアクセサーと 1 つのカスタム関数をリストに追加します(前述の標準アクセサーも含まれます)。

カスタム関数は静的メソッドであることに注意してください。上記の例では、カスタム関数は MyFunctions というクラスの calc という静的メソッドであり、型 MyThing の単一パラメーターを取ります。

MyThing の型を持つペイロードを持つ Message があるとします。さらに、MyThing から MyObject というオブジェクトを作成し、そのオブジェクトで calc というカスタム関数を呼び出すために何らかのアクションを実行する必要があるとします。

標準のプロパティアクセサーは MyThing から MyObject を取得する方法を知らないため、カスタムプロパティアクセサーを作成および構成することができます。その結果、最終的な式は "#barcalc(payload.myObject)" になる可能性があります。

ファクトリ Bean には、SpEL 評価中に使用される TypeLocator をカスタマイズできる別のプロパティ(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 を構成する代わりに、これらのコンポーネントを 1 つ以上追加することができ、フレームワークはそれらをデフォルトの 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/> は解析され、id をキーとして、静的 Method を値として、マップエントリとして integrationEvaluationContext の functionsMap に追加されます。

  • integrationEvaluationContext ファクトリ Bean は新しい StandardEvaluationContext インスタンスを作成し、デフォルトの PropertyAccessor インスタンス、BeanResolver、カスタム関数で構成されます。

  • その EvaluationContext インスタンスは ExpressionEvaluatingTransformer Bean に注入されます。

Java 構成を使用して SpEL 関数を提供するには、各関数に対して SpelFunctionFactoryBean Bean を宣言できます。次の例は、カスタム関数を作成する方法を示しています。

@Bean
public SpelFunctionFactoryBean xpath() {
    return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate");
}
親コンテキストで宣言された SpEL 関数は、すべての子コンテキストでも使用可能になります。コンテキストごとに異なる BeanResolver が必要なため、各コンテキストには integrationEvaluationContext ファクトリ Bean の独自のインスタンスがありますが、関数宣言は継承され、同じ名前の SpEL 関数を宣言することでオーバーライドできます。

組み込み SpEL 関数

Spring Integration は、起動時にアプリケーションコンテキストに自動的に登録される次の標準機能を提供します。

  • #jsonPath: 指定されたオブジェクトの "jsonPath" を評価します。この関数は、Jayway JsonPath ライブラリ [GitHub] (英語) に委譲する JsonPathUtils.evaluate(…​) を呼び出します。次のリストは、いくつかの使用例を示しています。

    <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 は、3 番目の(オプションの)パラメーターである com.jayway.jsonpath.Filter [GitHub] (英語) の配列もサポートしています。これは、Bean または Bean メソッドへの参照によって提供できます(たとえば)。

    この関数を使用するには、Jayway JsonPath ライブラリ(json-path.jar)がクラスパス上にある必要があります。そうでない場合、#jsonPath SpEL 関数は登録されません。

    JSON の詳細については、Transformer の "JSON Transformers" を参照してください。

  • #xpath: 提供されたオブジェクトの "xpath" を評価するため。XML および XPath の詳細については、XML サポート - XML ペイロードの処理を参照してください。

プロパティアクセサー

Spring Integration は、SpEL カスタム PropertyAccessor (Javadoc) 実装を作成できるネームスペースサポートを提供します。<spel-property-accessors/> コンポーネントを使用して、カスタム PropertyAccessor インスタンスのリストをフレームワーク全体で使用される EvaluationContext に提供できます。前述のファクトリ Bean を構成する代わりに、これらのコンポーネントを 1 つ以上追加できます。フレームワークは、アクセサーをデフォルトの integrationEvaluationContext ファクトリ Bean に自動的に追加します。次の例は、その方法を示しています。

<int:spel-property-accessors>
	<bean id="jsonPA" class="org.springframework.integration.json.JsonPropertyAccessor"/>
	<ref bean="fooPropertyAccessor"/>
</int:spel-property-accessors>

前の例では、2 つのカスタム PropertyAccessor インスタンスが EvaluationContext に(宣言された順序で)挿入されます。

Java 構成を使用して PropertyAccessor インスタンスを提供するには、SpelPropertyAccessorRegistrar Bean を spelPropertyAccessorRegistrar (IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME 定数で指定)の名前で宣言する必要があります。次の例は、Java を使用して 2 つのカスタム 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

  • ReflectivePropertyAccessor