サービスアクティベーター
サービスアクティベータは、Spring が管理するオブジェクトを入力チャネルに接続して、サービスのロールを果たすようにするためのエンドポイント型です。サービスが出力を生成する場合、出力チャネルにも接続される場合があります。または、出力生成サービスを処理パイプラインまたはメッセージフローの最後に配置することもできます。この場合、受信メッセージの replyChannel
ヘッダーを使用できます。これは、出力チャネルが定義されていない場合のデフォルトの動作です。ここで説明するほとんどの構成オプションと同様に、実際には同じ動作が他のほとんどのコンポーネントに適用されます。
サービスアクティベーターは、基本的に、入力メッセージ (ペイロードとヘッダー) を含むオブジェクトのメソッドを呼び出すための汎用エンドポイントです。その内部ロジックは MessageHandler
に基づいており、MessageHandler
は特定の使用例 (例: DefaultMessageSplitter
、AggregatingMessageHandler
、SftpMessageHandler
、JpaOutboundGateway
など) で考えられる実装です。したがって、このリファレンスマニュアルでメンションされている送信 ゲートウェイおよび送信 チャネルアダプターは、このサービスの特定の拡張機能として扱う必要があります。アクティベーターエンドポイント。それらはすべて、最終的にはオブジェクトのメソッドを呼び出します。
Service Activator の構成
Java とアノテーションの構成では、それぞれのサービスメソッドを @ServiceActivator
アノテーションでマークするだけで十分です。フレームワークは、メッセージが入力チャネルから消費されるときにそれを呼び出します。
public class SomeService {
@ServiceActivator(inputChannel = "exampleChannel")
public void exampleHandler(SomeData payload) {
...
}
}
詳細については、アノテーションサポートを参照してください。
Java、Groovy または Kotlin DSL の場合、IntegrationFlow
の .handle()
演算子はサービスアクティベーターを表します。
Java DSL
Kotlin DSL
Groovy DSL
@Bean
public IntegrationFlow someFlow() {
return IntegrationFlow
.from("exampleChannel")
.handle(someService, "exampleHandler")
.get();
}
@Bean
fun someFlow() =
integrationFlow("exampleChannel") {
handle(someService, "exampleHandler")
}
@Bean
someFlow() {
integrationFlow 'exampleChannel',
{
handle someService, 'exampleHandler'
}
}
DSL の詳細については、次の各章を参照してください。
XML 構成を使用するときにサービスアクティベーターを作成するには、次の例に示すように、"input-channel" 属性と "ref" 属性を指定した 'service-activator' 要素 を使用します。
<int:service-activator input-channel="exampleChannel" ref="exampleHandler"/>
前述の構成では、次のメッセージング要件のいずれかを満たす exampleHandler
からすべてのメソッドを選択します。
@ServiceActivator
のアノテーションが付けられていますpublic
requiresReply == true
の場合、void
を返さない
実行時の呼び出しのターゲットメソッドは、各リクエストメッセージに対して payload
型によって、またはそのようなメソッドがターゲットクラスに存在する場合は Message<?>
型へのフォールバックとして選択されます。
バージョン 5.0 以降では、1 つのサービスメソッドをすべての不一致ケースのフォールバックとして @org.springframework.integration.annotation.Default
でマークできます。これは、変換後にターゲットメソッドが呼び出されるコンテンツ型変換を使用する場合に便利です。
オブジェクトの明示的に定義されたメソッドに委譲するには、次の例に示すように、method
属性を追加できます。
<int:service-activator input-channel="exampleChannel" ref="somePojo" method="someMethod"/>
いずれの場合でも、サービスメソッドが null 以外の値を返すと、エンドポイントは応答メッセージを適切な応答チャネルに送信しようとします。応答チャネルを決定するには、次の例に示すように、エンドポイント構成で output-channel
が提供されたかどうかを最初に確認します。
<int:service-activator input-channel="exampleChannel" output-channel="replyChannel"
ref="somePojo" method="someMethod"/>
メソッドが結果を返し、output-channel
が定義されていない場合、フレームワークはリクエストメッセージの replyChannel
ヘッダー値をチェックします。その値が利用可能な場合は、その型をチェックします。MessageChannel
の場合、応答メッセージはそのチャネルに送信されます。String
の場合、エンドポイントはチャネル名をチャネルインスタンスに解決しようとします。チャネルを解決できない場合は、DestinationResolutionException
がスローされます。解決できる場合、メッセージはそこに送信されます。リクエストメッセージに replyChannel
ヘッダーがなく、reply
オブジェクトが Message
である場合、その replyChannel
ヘッダーがターゲットの宛先について調べられます。これは、Spring Integration でリクエストと応答のメッセージングに使用される手法であり、リターンアドレスパターンの例でもあります。
メソッドが結果を返し、それを破棄してフローを終了したい場合は、NullChannel
に送信するように output-channel
を構成する必要があります。便宜上、フレームワークは nullChannel
という名前で登録します。詳細については、"特別チャンネル" を参照してください。
サービスアクティベータは、応答メッセージを生成するために必要ではないコンポーネントの 1 つです。メソッドが null
を返す場合、または void
戻り型を持っている場合、サービスアクティベータはメソッド呼び出しの後にシグナルなしで終了します。この動作は、AbstractReplyProducingMessageHandler.requiresReply
オプションによって制御できます。このオプションは、XML 名前空間で構成するときに requires-reply
として公開されます。フラグが true
に設定され、メソッドが null を返す場合、ReplyRequiredException
がスローされます。
サービスメソッドの引数は、メッセージまたは任意の型のいずれかです。後者の場合、メッセージから抽出され、サービスメソッドに注入されるメッセージペイロードであると想定されます。Spring Integration を使用する場合、POJO モデルをフォローし、促進するため、一般的にこのアプローチをお勧めします。アノテーションサポートに従って、引数には @Header
または @Headers
アノテーションが付いている場合もあります。
サービスメソッドに引数を指定する必要はありません。つまり、イベントスタイルのサービスアクティベーター(サービスメソッドの呼び出しだけが重要)を実装でき、メッセージの内容を心配する必要はありません。null JMS メッセージと考えてください。このような実装の使用例の例は、入力チャネルに置かれたメッセージの単純なカウンターまたはモニターです。 |
次の例に示すように、バージョン 4.1 以降、フレームワークはメッセージプロパティ(payload
および headers
)を Java 8 Optional
POJO メソッドパラメーターに正しく変換します。
public class MyBean {
public String computeValue(Optional<String> payload,
@Header(value="foo", required=false) String foo1,
@Header(value="foo") Optional<String> foo2) {
if (payload.isPresent()) {
String value = payload.get();
...
}
else {
...
}
}
}
通常、カスタムサービスアクティベーターハンドラーの実装を他の <service-activator>
定義で再利用できる場合は、ref
属性を使用することをお勧めします。ただし、カスタムサービスアクティベーターハンドラーの実装が <service-activator>
の単一の定義内でのみ使用される場合、次の例に示すように、内部 Bean 定義を提供できます。
<int:service-activator id="exampleServiceActivator" input-channel="inChannel"
output-channel = "outChannel" method="someMethod">
<beans:bean class="org.something.ExampleServiceActivator"/>
</int:service-activator>
同じ <service-activator> 構成で ref 属性と内部ハンドラー定義の両方を使用することは許可されません。曖昧な状態を作成し、例外がスローされるためです。 |
ref 属性が AbstractMessageProducingHandler を継承する Bean を参照する場合(フレームワーク自体が提供するハンドラーなど)、出力チャネルをハンドラーに直接注入することにより、構成が最適化されます。この場合、各 ref は、個別の Bean インスタンス(または prototype -scoped Bean)にするか、内部 <bean/> 構成型を使用する必要があります。誤って複数の Bean から同じメッセージハンドラーを参照すると、構成例外が発生します。 |
サービスアクティベーターと Spring 式言語 (SpEL)
Spring Integration 2.0 以降、サービスアクティベーターも SpEL の恩恵を受けることができます。
例: 次のように、ref
属性の Bean を指すことなく、または内部 Bean 定義として含めることなく、Bean メソッドを呼び出すことができます。
<int:service-activator input-channel="in" output-channel="out"
expression="@accountService.processAccount(payload, headers.accountId)"/>
<bean id="accountService" class="thing1.thing2.Account"/>
上記の構成では、ref
または内部 Bean を使用して 'accountService' を挿入する代わりに、SpEL の @beanId
表記法を使用して、メッセージペイロードと互換性のある型を受け取るメソッドを呼び出します。また、ヘッダー値も渡します。有効な SpEL 式は、メッセージ内の任意のコンテンツに対して評価できます。単純なシナリオでは、次の例に示すように、すべてのロジックをそのような式にカプセル化できる場合、サービスアクティベーターは Bean を参照する必要はありません。
<int:service-activator input-channel="in" output-channel="out" expression="payload * 2"/>
上記の構成では、サービスロジックはペイロード値に 2 を掛けます。SpEL を使用すると、比較的簡単に処理できます。
サービスアクティベーターの設定の詳細については、Java DSL の章のサービスアクティベーターと .handle()
メソッドを参照してください。
非同期サービスアクティベーター
サービスアクティベーターは、呼び出しスレッドによって呼び出されます。入力チャネルが SubscribableChannel
または PollableChannel
のポーラースレッドの場合、これはアップストリームスレッドです。サービスが CompletableFuture<?>
を返す場合、デフォルトのアクションは、それを出力(または応答)チャネルに送信されるメッセージのペイロードとして送信することです。バージョン 4.3 から、async
属性を true
に設定できるようになりました(Java 構成の使用時に setAsync(true)
を使用)。この async
属性が true
に設定されているときにサービスが CompletableFuture<?>
を返すと、呼び出し元のスレッドはすぐに解放され、応答メッセージが(サービス内から)スレッドで送信され、将来を完了します。これは、ポーラースレッドがフレームワーク内で他のサービスを実行するために解放されるため、PollableChannel
を使用する長時間実行サービスに特に有利です。
サービスが Exception
で将来を完了すると、通常のエラー処理が発生します。ErrorMessage
は、存在する場合、errorChannel
メッセージヘッダーに送信されます。そうでない場合、ErrorMessage
はデフォルトの errorChannel
に送信されます(使用可能な場合)。
バージョン 6.1 以降、AbstractMessageProducingHandler
の出力チャネルが ReactiveStreamsSubscribableChannel
に設定されている場合、非同期モードはデフォルトでオンになります。ハンドラーの結果がリアクティブ型または CompletableFuture<?>
ではない場合、出力チャネルの型に関係なく、通常の応答生成プロセスが発生します。
詳細については、Reactive Streams サポートも参照してください。
サービスアクティベーターとメソッドの戻り値の型
サービスメソッドは、応答メッセージペイロードになる任意の型を返すことができます。この場合、新しい Message<?>
オブジェクトが作成され、リクエストメッセージのすべてのヘッダーがコピーされます。対話が POJO メソッド呼び出しに基づいている場合、これはほとんどの Spring Integration MessageHandler
実装で同じように機能します。
メソッドから完全な Message<?>
オブジェクトを返すこともできます。ただし、Transformer とは異なり、Service Activator の場合、返されたメッセージにヘッダーがまだ存在しない場合、このメッセージはリクエストメッセージからヘッダーをコピーすることによって変更されることに注意してください。そのため、メソッドパラメーターが Message<?>
で、サービスメソッドの既存のヘッダーのすべてではなく一部をコピーすると、それらは応答メッセージに再表示されます。応答メッセージからヘッダーを削除するのは Service Activator の責任ではなく、疎結合の原則を追求するために、統合フローに HeaderFilter
を追加することをお勧めします。別の方法として、Service Activator の代わりに Transformer を使用することもできますが、その場合、完全な Message<?>
を返す場合、メソッドは、リクエストメッセージヘッダーのコピー (必要な場合) を含め、メッセージを完全に処理します。重要なフレームワークヘッダー ( replyChannel
、errorChannel
など) が存在する場合は、保持する必要があることを確認する必要があります。