スクリプトのサポート

Spring Integration 2.1 は、Java バージョン 6 で導入された JSR223 Scripting for Java 仕様 (英語) のサポートを追加しました。サポートされている任意の言語(Ruby、JRuby、Groovy、Kotlin を含む)で記述されたスクリプトを使用して、Spring 式言語と同様に、さまざまな統合コンポーネントのロジックを提供できます。(SpEL)は Spring Integration で使用されます。JSR223 の詳細については、ドキュメント [Oracle] を参照してください。

この依存関係をプロジェクトに含める必要があります。

Maven
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-scripting</artifactId>
    <version>6.0.5</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-scripting:6.0.5"

さらに、スクリプトエンジンの実装を追加する必要があります。JRuby、Jython。

バージョン 5.2 以降、Spring Integration は Kotlin Jsr223 サポートを提供します。これらの依存関係をプロジェクトに追加して、プロジェクトを機能させる必要があります。

Maven
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-script-util</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-compiler-embeddable</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-scripting-compiler-embeddable</artifactId>
    <scope>runtime</scope>
</dependency>
Gradle
runtime 'org.jetbrains.kotlin:kotlin-script-util'
runtime 'org.jetbrains.kotlin:kotlin-compiler-embeddable'
runtime 'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable'

KotlinScriptExecutor は、提供されている kotlin 言語インジケータによって選択されるか、スクリプトファイルに .kts 拡張子が付いています。

JVM スクリプト言語を使用するには、その言語の JSR223 実装をクラスパスに含める必要があります。Groovy (英語) および JRuby (英語) プロジェクトは、標準ディストリビューションで JSR233 サポートを提供します。

さまざまな JSR223 言語実装がサードパーティによって開発されています。特定の実装の Spring Integration との互換性は、仕様と実装者の仕様の解釈にどれだけ準拠しているかによって異なります。
スクリプト言語として Groovy を使用する場合、Groovy に固有の追加機能を提供するため、Spring-Integration の Groovy サポートを使用することをお勧めします。ただし、このセクションも関連しています。

スクリプト構成

統合要件の複雑さに応じて、XML 構成の CDATA として、またはスクリプトを含む Spring リソースへの参照として、スクリプトをインラインで提供できます。スクリプトのサポートを有効にするために、Spring Integration は ScriptExecutingMessageProcessor を定義します。ScriptExecutingMessageProcessor は、メッセージペイロードを payload という名前の変数にバインドし、メッセージヘッダーを headers 変数にバインドします。どちらもスクリプト実行コンテキスト内でアクセスできます。必要なのは、これらの変数を使用するスクリプトを書くことだけです。次のペアの例は、フィルターを作成するサンプル構成を示しています。

Java DSL
@Bean
public IntegrationFlow scriptFilter() {
    return f -> f.filter(Scripts.processor("some/path/to/ruby/script/RubyFilterTests.rb"));
}
...
@Bean
public Resource scriptResource() {
	return new ByteArrayResource("headers.type == 'good'".getBytes());
}

@Bean
public IntegrationFlow scriptFilter() {
	return f -> f.filter(Scripts.processor(scriptResource()).lang("groovy"));
}
XML
<int:filter input-channel="referencedScriptInput">
   <int-script:script location="some/path/to/ruby/script/RubyFilterTests.rb"/>
</int:filter>

<int:filter input-channel="inlineScriptInput">
     <int-script:script lang="groovy">
     <![CDATA[
     return payload == 'good'
   ]]>
  </int-script:script>
</int:filter>

前の例が示すように、スクリプトはインラインで含めることも、リソースの場所を参照して(location 属性を使用して)含めることもできます。さらに、lang 属性は、言語名(またはその JSR223 エイリアス)に対応します。

スクリプトをサポートする他の Spring Integration エンドポイント要素には routerservice-activatortransformersplitter が含まれます。それぞれの場合のスクリプト構成は、上記と同じです(エンドポイント要素を除く)。

スクリプトサポートのもう 1 つの便利な機能は、アプリケーションコンテキストを再起動せずにスクリプトを更新(再読み込み)できることです。これを行うには、次の例に示すように、script 要素で refresh-check-delay 属性を指定します。

Java DSL
Scripts.processor(...).refreshCheckDelay(5000)
}
XML
<int-script:script location="..." refresh-check-delay="5000"/>

上記の例では、スクリプトの場所は 5 秒ごとに更新が確認されます。スクリプトが更新された場合、更新から 5 秒より後に行われた呼び出しはすべて、新しいスクリプトを実行します。

次の例を考えてみましょう。

Java DSL
Scripts.processor(...).refreshCheckDelay(0)
}
XML
<int-script:script location="..." refresh-check-delay="0"/>

前述の例では、スクリプトの変更が発生するとすぐにコンテキストが更新され、「リアルタイム」構成の簡単なメカニズムが提供されます。負の値は、アプリケーションコンテキストの初期化後にスクリプトがリロードされないことを意味します。これがデフォルトの動作です。次の例は、更新しないスクリプトを示しています。

Java DSL
Scripts.processor(...).refreshCheckDelay(-1)
}
XML
<int-script:script location="..." refresh-check-delay="-1"/>
インラインスクリプトはリロードできません。
スクリプト変数のバインド

スクリプトがスクリプトの実行コンテキストに外部から提供された変数を参照できるようにするには、変数バインディングが必要です。デフォルトでは、payload と headers がバインディング変数として使用されます。次の例に示すように、<variable> 要素(または ScriptSpec.variables() オプション)を使用して、追加の変数をスクリプトにバインドできます。

Java DSL
Scripts.processor("foo/bar/MyScript.py")
    .variables(Map.of("var1", "thing1", "var2", "thing2", "date", date))
}
XML
<script:script lang="py" location="foo/bar/MyScript.py">
    <script:variable name="var1" value="thing1"/>
    <script:variable name="var2" value="thing2"/>
    <script:variable name="date" ref="date"/>
</script:script>

前の例に示すように、スクリプト変数をスカラー値または Spring Bean 参照にバインドできます。payload と headers は、まだバインディング変数として含まれていることに注意してください。

Spring Integration 3.0 では、variable 要素に加えて、variables 属性が導入されています。この属性と variable 要素は相互に排他的ではなく、1 つの script コンポーネント内で組み合わせることができます。ただし、変数は、どこに定義されているかに関係なく、一意である必要があります。また、Spring Integration 3.0 以降、次の例に示すように、インラインスクリプトでも変数バインディングを使用できます。

<service-activator input-channel="input">
    <script:script lang="ruby" variables="thing1=THING1, date-ref=dateBean">
        <script:variable name="thing2" ref="thing2Bean"/>
        <script:variable name="thing3" value="thing2"/>
        <![CDATA[
            payload.foo = thing1
            payload.date = date
            payload.bar = thing2
            payload.baz = thing3
            payload
        ]]>
    </script:script>
</service-activator>

上記の例は、インラインスクリプト、variable 要素、variables 属性の組み合わせを示しています。variables 属性にはコンマ区切り値が含まれ、各セグメントには変数とその値の "=" で区切られたペアが含まれます。前の例の date-ref 変数のように、変数名の末尾に -ref を付けることができます。つまり、バインディング変数の名前は date ですが、値はアプリケーションコンテキストからの dateBean Bean への参照です。これは、プロパティプレースホルダーの構成またはコマンドライン引数を使用する場合に便利です。

変数の生成方法をさらに制御する必要がある場合は、ScriptVariableGenerator 戦略を使用する独自の Java クラスを実装できます。この戦略は、次のインターフェースで定義されます。

public interface ScriptVariableGenerator {

    Map<String, Object> generateScriptVariables(Message<?> message);

}

このインターフェースでは、generateScriptVariables(Message) メソッドを実装する必要があります。メッセージ引数を使用すると、メッセージペイロードとヘッダーで使用可能なデータにアクセスでき、戻り値はバインドされた変数の Map です。このメソッドは、メッセージに対してスクリプトが実行されるたびに呼び出されます。次の例は、ScriptVariableGenerator の実装を提供し、script-variable-generator 属性でそれを参照する方法を示しています。

Java DSL
Scripts.processor("foo/bar/MyScript.groovy")
    .variableGenerator(new foo.bar.MyScriptVariableGenerator())
}
XML
<int-script:script location="foo/bar/MyScript.groovy"
        script-variable-generator="variableGenerator"/>

<bean id="variableGenerator" class="foo.bar.MyScriptVariableGenerator"/>

script-variable-generator が提供されない場合、スクリプトコンポーネントは DefaultScriptVariableGenerator を使用します。DefaultScriptVariableGenerator は、提供された <variable> 要素を、generateScriptVariables(Message) メソッドで Message からの payload および headers 変数とマージします。

script-variable-generator 属性と <variable> 要素の両方を提供することはできません。それらは相互に排他的です。
GraalVM Polyglot

バージョン 6.0 以降、フレームワークは GraalVM Polyglot API (英語) に基づく PolyglotScriptExecutor を提供します。JavaScript の JSR223 エンジンの実装は、Java から単独で削除されましたが、この新しいスクリプトエグゼキュータを使用することで置き換えられました。GraalVM で JavaScript サポートを有効にする方法と、スクリプト変数を介して伝達できる構成オプション (英語) について詳しくは、こちらを参照してください。デフォルトでは、フレームワークは共有 Polyglot Context で allowAllAccess を true に設定します。これにより、ホスト JVM との対話が可能になります。

  • 新しいスレッドの作成と使用。

  • パブリックホストクラスへのアクセス。

  • クラスパスにエントリを追加することによる新しいホストクラスのロード。

  • 新しいメンバーをポリグロットバインディングにエクスポートします。

  • ホストシステムでの無制限の IO 操作。

  • 実験的なオプションを渡します。

  • 新しいサブプロセスの作成と使用。

  • プロセス環境変数へのアクセス。

これは、org.graalvm.polyglot.Context.Builder を受け入れるオーバーロードされた PolyglotScriptExecutor コンストラクターを介してカスタマイズできます。

この JavaScript サポートを有効にするには、js コンポーネントがインストールされた GraalVM を使用する必要があります。通常の JVM を使用する場合は、org.graalvm.sdk:graal-sdk および org.graalvm.js:js 依存関係を含める必要があります。