構成
Spring Integration は、多くの構成オプションを提供します。どのオプションを選択するかは、特定のニーズと、どのレベルで作業するかによって異なります。一般的な Spring フレームワークと同様に、さまざまな手法を組み合わせて、手元の問題に合わせて調整できます。例: 大部分の構成で XSD ベースの名前空間を選択し、それをアノテーションで構成する少数のオブジェクトと組み合わせることができます。可能な限り、2 つは一貫した命名を提供します。XSD スキーマで定義された XML 要素はアノテーションの名前と一致し、それらの XML 要素の属性はアノテーションプロパティの名前と一致します。API を直接使用することもできますが、ほとんどの開発者は、より高いレベルのオプションのいずれか、名前空間ベースの構成とアノテーション駆動型の構成の組み合わせを選択することが期待されます。
名前空間サポート
Spring Integration コンポーネントを、エンタープライズ統合の用語と概念に直接マップする XML 要素で構成できます。多くの場合、要素名はエンタープライズ統合パターン (英語) ブックの要素名と一致します。
Spring 構成ファイル内で Spring Integration のコア名前空間のサポートを有効にするには、最上位の 'beans' 要素に次の名前空間参照とスキーママッピングを追加します。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd">
(Spring Integration に特有の行を強調しました)
"xmlns:" の後に任意の名前を選択できます。わかりやすくするために int
(Integration の略)を使用していますが、別の略語を使用することもできます。一方、XML エディターまたは IDE サポートを使用している場合は、自動補完機能を使用できるため、わかりやすくするために長い名前を使用する必要があります。または、次の例に示すように、Spring Integration スキーマをプライマリ名前空間として使用する構成ファイルを作成できます。
<beans:beans xmlns="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd">
(Spring Integration に特有の行を強調しました)
この代替を使用する場合、Spring Integration 要素にプレフィックスは必要ありません。一方、同じ構成ファイル内で汎用 Spring Bean を定義する場合、Bean エレメントにはプレフィックス(<beans:bean …/>
)が必要です。一般に、構成ファイル自体を(責任またはアーキテクチャーレイヤーに基づいて)モジュール化することをお勧めします。これらのファイル内ではジェネリクス Bean はほとんど必要ないため、統合に焦点を当てた構成ファイルで後者のアプローチを使用するのが適切であることがわかります。このドキュメントでは、統合ネームスペースがプライマリであると想定しています。
Spring Integration は、他の多くの名前空間を提供します。実際、名前空間のサポートを提供する各アダプター型(JMS、ファイルなど)は、個別のスキーマ内でその要素を定義します。これらの要素を使用するには、xmlns
エントリと対応する schemaLocation
マッピングで必要な名前空間を追加します。例: 次のルート要素は、これらの名前空間宣言のいくつかを示しています。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
xmlns:int-rmi="http://www.springframework.org/schema/integration/rmi"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
https://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration/jms
https://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/mail
https://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd
http://www.springframework.org/schema/integration/rmi
https://www.springframework.org/schema/integration/rmi/spring-integration-rmi.xsd
http://www.springframework.org/schema/integration/ws
https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
...
</beans>
このリファレンスマニュアルでは、対応する章のさまざまな要素の具体例を示します。ここで認識すべき主なことは、各名前空間 URI とスキーマの場所の命名の一貫性です。
タスクスケジューラの構成
Spring Integration では、ApplicationContext
はメッセージバスの中心的なロールを果たします。いくつかの構成オプションのみを考慮する必要があります。最初に、主要な TaskScheduler
インスタンスを制御したい場合があります。そのためには、taskScheduler
という名前の単一の Bean を提供します。これは、次のように定数としても定義されます。
IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME
デフォルトでは、Spring Integration は、Spring Framework リファレンスマニュアルのタスクの実行とスケジューリングセクションに従って、ThreadPoolTaskScheduler
のインスタンスに依存しています。デフォルトの TaskScheduler
は 10 個のスレッドのプールで自動的に起動しますが、グローバルプロパティを参照してください。代わりに独自の TaskScheduler
インスタンスを提供する場合、"autoStartup" プロパティを false
に設定するか、独自のプールサイズ値を提供できます。
ポーリングコンシューマーが構成で明示的なタスクエグゼキューター参照を提供すると、ハンドラーメソッドの呼び出しはメインスケジューラープールではなく、エグゼキューターのスレッドプール内で発生します。ただし、エンドポイントのポーラーにタスクエグゼキューターが提供されていない場合、メインスケジューラーのスレッドの 1 つによって呼び出されます。
ポーラースレッドで長時間実行されるタスクを実行しないでください。代わりにタスクエグゼキューターを使用してください。ポーリングエンドポイントが多数ある場合、プールサイズを大きくしない限り、スレッド不足が発生する可能性があります。また、ポーリングコンシューマーのデフォルト receiveTimeout は 1 秒です。この時間はポーラースレッドがブロックするため、このようなエンドポイントが多数存在する場合は、タスクエグゼキューターを使用して、飢 again を回避することをお勧めします。あるいは、receiveTimeout を減らすことができます。 |
入力チャネルがキューベース(つまり、ポーリング可能)チャネルの 1 つである場合、エンドポイントはポーリングコンシューマーです。イベント駆動型コンシューマーとは、キューではなくディスパッチャーを備えた入力チャネルを持つコンシューマーです(つまり、サブスクライブ可能です)。そのようなエンドポイントには、ハンドラーが直接呼び出されるため、ポーラー構成がありません。 |
JEE コンテナーで実行する場合、デフォルトの
|
カスタム TaskScheduler がアプリケーションコンテキストで構成されている場合(上記の DefaultManagedTaskScheduler のように)、フレームワークによって提供される ErrorMessage`s sent to the error channel, as is done with the default `TaskScheduler Bean として例外を処理できるように、MessagePublishingErrorHandler (integrationMessagePublishingErrorHandler Bean)を提供することをお勧めします。 |
詳細については、エラー処理も参照してください。
グローバルプロパティ
特定のグローバルフレームワークプロパティは、クラスパスでプロパティファイルを提供することでオーバーライドできます。
デフォルトのプロパティは org.springframework.integration.context.IntegrationProperties
クラスにあります。次のリストは、デフォルト値を示しています。
spring.integration.channels.autoCreate=true (1)
spring.integration.channels.maxUnicastSubscribers=0x7fffffff (2)
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff (3)
spring.integration.taskScheduler.poolSize=10 (4)
spring.integration.messagingTemplate.throwExceptionOnLateReply=false (5)
spring.integration.readOnly.headers= (6)
spring.integration.endpoints.noAutoStartup= (7)
spring.integration.channels.error.requireSubscribers=true (8)
spring.integration.channels.error.ignoreFailures=true (9)
1 | true の場合、input-channel インスタンスは、アプリケーションコンテキストで明示的に検出されない場合、DirectChannel インスタンスとして自動的に宣言されます。 |
2 | DirectChannel などで許可されるデフォルトのサブスクライバー数を設定します。誤って同じチャネルに複数のエンドポイントをサブスクライブすることを避けるために使用できます。max-subscribers 属性を設定することにより、個々のチャネルでこれをオーバーライドできます。 |
3 | このプロパティは、たとえば PublishSubscribeChannel で許可されるデフォルトのサブスクライバー数を提供します。これは、同じチャネルに予期しない数のエンドポイントを誤ってサブスクライブすることを回避するために使用できます。max-subscribers 属性を設定することにより、個々のチャネルでこれをオーバーライドできます。 |
4 | デフォルトの taskScheduler Bean で使用可能なスレッドの数。タスクスケジューラの構成を参照してください。 |
5 | true の場合、ゲートウェイが応答を予期していない場合、ゲートウェイ応答チャネルに到着したメッセージは例外をスローします(送信スレッドがタイムアウトしたか、すでに応答を受信したため)。 |
6 | ヘッダーコピー操作中に Message インスタンスに入力しないメッセージヘッダー名のコンマ区切りリスト。このリストは DefaultMessageBuilderFactory Bean によって使用され、MessageBuilder (MessageBuilder ヘルパークラスを参照)を介してメッセージを作成するために使用される IntegrationMessageHeaderAccessor インスタンス(MessageHeaderAccessor API を参照)に伝搬されます。デフォルトでは、MessageHeaders.ID と MessageHeaders.TIMESTAMP のみがメッセージの構築中にコピーされません。バージョン 4.3.2 以降。 |
7 | アプリケーションの起動時に自動的に起動しない AbstractEndpoint Bean 名パターンのコンマ区切りリスト(xxx* 、xxx 、*xxx または xxx*yyy )。これらのエンドポイントは、Bean 名によって Control Bus (制御バスを参照)、SmartLifecycleRoleController でのロール(エンドポイントのロールを参照)、Lifecycle Bean インジェクションによって後で手動で開始できます。auto-startup XML アノテーションまたは autoStartup アノテーション属性を指定するか、Bean 定義で AbstractEndpoint.setAutoStartup() を呼び出すことにより、このグローバルプロパティの効果を明示的にオーバーライドできます。バージョン 4.3.12 以降。 |
8 | デフォルトのグローバル errorChannel を requireSubscribers オプションで構成する必要があることを示すブールフラグ。バージョン 5.4.3 以降。詳細については、エラー処理を参照してください。 |
9 | デフォルトのグローバル errorChannel がディスパッチングエラーを無視し、メッセージを次のハンドラーに渡す必要があることを示すブールフラグ。バージョン 5.5 以降。 |
これらのプロパティは、/META-INF/spring.integration.properties
ファイルをクラスパスに追加するか、org.springframework.integration.context.IntegrationProperties
インスタンスの場合は IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME
Bean を追加することでオーバーライドできます。すべてのプロパティを指定する必要はありません。オーバーライドするプロパティのみを指定してください。
バージョン 5.1 以降、DEBUG
ロジックレベルが org.springframework.integration
カテゴリに対してオンになっている場合、アプリケーションコンテキストの起動後に、マージされたすべてのグローバルプロパティがログに出力されます。出力は次のようになります。
Spring Integration global properties:
spring.integration.endpoints.noAutoStartup=fooService*
spring.integration.taskScheduler.poolSize=20
spring.integration.channels.maxUnicastSubscribers=0x7fffffff
spring.integration.channels.autoCreate=true
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff
spring.integration.readOnly.headers=
spring.integration.messagingTemplate.throwExceptionOnLateReply=true
アノテーションサポート
メッセージエンドポイントを構成するための XML 名前空間のサポートに加えて、アノテーションも使用できます。まず、Spring Integration は、クラスレベルの @MessageEndpoint
をステレオタイプアノテーションとして提供します。つまり、Spring の @Component
アノテーションが付けられているため、Spring のコンポーネントスキャンによって Bean 定義として自動的に認識されます。
さらに重要なのは、さまざまなメソッドレベルのアノテーションです。それらは、アノテーション付きメソッドがメッセージを処理できることを示しています。次の例は、クラスレベルとメソッドレベルの両方のアノテーションを示しています。
@MessageEndpoint
public class FooService {
@ServiceActivator
public void processMessage(Message message) {
...
}
}
メソッドがメッセージを「処理」することの正確な意味は、特定のアノテーションに依存します。Spring Integration で使用できるアノテーションは次のとおりです。
@Aggregator
( アグリゲーターを参照してください)@Filter
( フィルターを参照してください)@Router
( ルーターを参照してください)@ServiceActivator
( サービスアクティベーターを参照してください)@Splitter
( スプリッターを参照してください)@Transformer
(Transformer を参照してください)@InboundChannelAdapter
( チャンネルアダプターを参照してください)@BridgeFrom
(Java 構成を使用したブリッジの構成を参照してください)@BridgeTo
(Java 構成を使用したブリッジの構成を参照してください)@MessagingGateway
( メッセージングゲートウェイを参照してください)@IntegrationComponentScan
( 構成と@EnableIntegration
を参照してください)
XML 構成をアノテーションと組み合わせて使用する場合、@MessageEndpoint アノテーションは必要ありません。<service-activator/> 要素の ref 属性から POJO 参照を設定する場合、メソッドレベルのアノテーションのみを提供できます。その場合、メソッドレベルの属性が <service-activator/> 要素に存在しない場合でも、アノテーションによってあいまいさが回避されます。 |
ほとんどの場合、アノテーション付きハンドラーメソッドは、パラメーターとして Message
型を必要としません。代わりに、次の例に示すように、メソッドパラメーター型はメッセージのペイロード型と一致できます。
public class ThingService {
@ServiceActivator
public void bar(Thing thing) {
...
}
}
メソッドパラメーターを MessageHeaders
の値からマップする必要がある場合、別のオプションはパラメーターレベルの @Header
アノテーションを使用することです。一般に、Spring Integration アノテーションが付けられたメソッドは、Message
自体、メッセージペイロード、ヘッダー値(@Header
を使用)をパラメーターとして受け入れることができます。実際、次の例に示すように、メソッドは組み合わせを受け入れることができます。
public class ThingService {
@ServiceActivator
public void otherThing(String payload, @Header("x") int valueX, @Header("y") int valueY) {
...
}
}
次の例に示すように、@Headers
アノテーションを使用して、すべてのメッセージヘッダーを Map
として提供することもできます。
public class ThingService {
@ServiceActivator
public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
...
}
}
アノテーションの値は SpEL 式(someHeader.toUpperCase() など)にすることもできます。これは、挿入する前にヘッダー値を操作する場合に便利です。また、オプションの required プロパティも提供します。このプロパティは、ヘッダー内で属性値を使用可能にする必要があるかどうかを指定します。required プロパティのデフォルト値は true です。 |
これらのアノテーションのいくつかについて、メッセージ処理メソッドが null 以外の値を返すと、エンドポイントは応答を送信しようとします。これは、このようなエンドポイントの出力チャネルが使用され(使用可能な場合)、REPLY_CHANNEL
メッセージヘッダー値がフォールバックとして使用されるという点で、両方の構成オプション(名前空間とアノテーション)で一貫しています。
エンドポイントの出力チャネルと応答チャネルメッセージヘッダーの組み合わせにより、パイプラインアプローチが可能になります。複数のコンポーネントに出力チャネルがあり、最終コンポーネントにより応答メッセージを応答チャネルに転送できます(元のリクエストメッセージで指定されています)。つまり、最終的なコンポーネントは元の送信者から提供された情報に依存し、結果として任意の数のクライアントを動的にサポートできます。これは、返信先アドレス (英語) パターンの例です。 |
ここに示す例に加えて、これらのアノテーションは、次の例が示すように、inputChannel
および outputChannel
プロパティもサポートします。
@Service
public class ThingService {
@ServiceActivator(inputChannel="input", outputChannel="output")
public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
...
}
}
これらのアノテーションの処理により、対応する XML コンポーネントと同じ Bean が作成されます。AbstractEndpoint
インスタンスおよび MessageHandler
インスタンス(または受信チャネルアダプターの MessageSource
インスタンス)。@Bean
メソッドのアノテーションを参照してください。Bean 名は次のパターンから生成されます: [componentName].[methodName].[decapitalizedAnnotationClassShortName]
。上記の例では、Bean の名前は AbstractEndpoint
の thingService.otherThing.serviceActivator
であり、MessageHandler
(MessageSource
)Bean の .handler
(.source
)サフィックスが追加された同じ名前です。このような名前は、@EndpointId
アノテーションとこれらのメッセージングアノテーションを併用してカスタマイズできます。MessageHandler
インスタンス(MessageSource
インスタンス)も、メッセージ履歴によって追跡することができます。
バージョン 4.0 以降、すべてのメッセージングアノテーションは SmartLifecycle
オプション(autoStartup
および phase
)を提供し、アプリケーションコンテキストの初期化でエンドポイントのライフサイクルを制御できるようにします。デフォルトでは、それぞれ true
と 0
になります。エンドポイント( `start()` や stop()
など)の状態を変更するには、BeanFactory
(またはオートワイヤー)を使用してエンドポイント Bean への参照を取得し、メソッドを呼び出すことができます。または、コマンドメッセージを Control Bus
に送信することもできます(制御バスを参照)。これらの目的のために、前の段落で前述した beanName
を使用する必要があります。
上記のアノテーション(特定のチャネル Bean が構成されていない場合)の解析後に自動的に作成されたチャネル、および対応するコンシューマーエンドポイントは、コンテキスト初期化の終わり近くで Bean として宣言されます。これらの Bean は他のサービスでオートワイヤーできますが、通常は通常のオートワイヤー処理中に定義がまだ利用できないため、
|
@Poller
アノテーションの使用
Spring Integration 4.0 より前のメッセージングアノテーションでは、inputChannel
が SubscribableChannel
への参照である必要がありました。PollableChannel
インスタンスの場合、<int:poller/>
を構成し、複合エンドポイントを PollingConsumer
にするために <int:bridge/>
要素が必要でした。次の例に示すように、バージョン 4.0 には @Poller
アノテーションが導入され、メッセージングアノテーションで poller
属性を直接設定できるようになりました。
public class AnnotationService {
@Transformer(inputChannel = "input", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
public String handle(String payload) {
...
}
}
@Poller
アノテーションは、単純な PollerMetadata
オプションのみを提供します。プロパティプレースホルダーを使用して、@Poller
アノテーションの属性(maxMessagesPerPoll
、fixedDelay
、fixedRate
、cron
)を構成できます。また、バージョン 5.1 以降、PollingConsumer
用の receiveTimeout
オプションも提供されます。より多くのポーリングオプション(たとえば、transaction
、advice-chain
、error-handler
など)を提供する必要がある場合は、PollerMetadata
を汎用 Bean として構成し、その Bean 名を @Poller
の value
属性として使用する必要があります。この場合、他の属性は許可されません(PollerMetadata
Bean で指定する必要があります)。inputChannel
が PollableChannel
であり、@Poller
が構成されていない場合、デフォルトの PollerMetadata
が使用されることに注意してください(アプリケーションコンテキストに存在する場合)。@Configuration
アノテーションを使用してデフォルトのポーラーを宣言するには、次の例のようなコードを使用します。
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
}
次の例は、デフォルトのポーラーの使用方法を示しています。
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
public String handle(String payload) {
...
}
}
次の例は、名前付きポーラーの使用方法を示しています。
@Bean
public PollerMetadata myPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
return pollerMetadata;
}
次の例は、デフォルトのポーラーを使用するエンドポイントを示しています。
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
poller = @Poller("myPoller"))
public String handle(String payload) {
...
}
}
バージョン 4.3.3 以降、@Poller
アノテーションには errorChannel
属性があり、基礎となる MessagePublishingErrorHandler
を簡単に構成できます。この属性は、<poller>
XML コンポーネントの error-channel
と同じロールを果たします。詳細については、エンドポイント名前空間のサポートを参照してください。
メッセージングアノテーションの poller()
属性は、reactive()
属性と相互に排他的です。詳細については、次のセクションを参照してください。
@Reactive
アノテーションの使用
ReactiveStreamsConsumer
はバージョン 5.0 から存在しますが、エンドポイントの入力チャネルが FluxMessageChannel
(または任意の org.reactivestreams.Publisher
実装)である場合にのみ適用されました。バージョン 5.3 以降、ターゲットメッセージハンドラーが入力チャネル型に関係なく ReactiveMessageHandler
である場合、そのインスタンスもフレームワークによって作成されます。@Reactive
サブアノテーション(上記の @Poller
と同様)は、バージョン 5.5 以降のすべてのメッセージングアノテーションに導入されました。オプションの Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>
Bean 参照を受け入れ、入力チャネル型およびメッセージハンドラーとは関係なく、ターゲットエンドポイントを ReactiveStreamsConsumer
インスタンスに変換します。この関数は、Flux.transform()
オペレーターから使用され、入力チャネルからのリアクティブストリームソースにカスタマイズ(publishOn()
、doOnNext()
、log()
、retry()
など)を適用します。
次の例は、最終的なサブスクライバーとプロデューサーに関係なく、公開スレッドを入力チャネルからその DirectChannel
に変更する方法を示しています。
@Bean
public Function<Flux<?>, Flux<?>> publishOnCustomizer() {
return flux -> flux.publishOn(Schedulers.parallel());
}
@ServiceActivator(inputChannel = "directChannel", reactive = @Reactive("publishOnCustomizer"))
public void handleReactive(String payload) {
...
}
メッセージングアノテーションの reactive()
属性は、poller()
属性と相互に排他的です。詳細については、@Poller
アノテーションの使用および Reactive Streams サポートを参照してください。
@InboundChannelAdapter
アノテーションの使用
バージョン 4.0 では、@InboundChannelAdapter
メソッドレベルのアノテーションが導入されました。アノテーション付きメソッドの MethodInvokingMessageSource
に基づいて SourcePollingChannelAdapter
統合コンポーネントを生成します。このアノテーションは <int:inbound-channel-adapter>
XML コンポーネントに類似しており、同じ制限があります。メソッドにはパラメーターを指定できません。戻り値の型は void
であってはなりません。(とオプションの @Poller
アノテーション、value
(必要な MessageChannel
Bean 名)と poller
: これは、2 つの属性があり、前述の)。MessageHeaders
を提供する必要がある場合は、Message<?>
戻り型を使用し、MessageBuilder
を使用して Message<?>
を作成します。MessageBuilder
を使用すると、MessageHeaders
を構成できます。次の例は、@InboundChannelAdapter
アノテーションの使用方法を示しています。
@InboundChannelAdapter("counterChannel")
public Integer count() {
return this.counter.incrementAndGet();
}
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000"))
public String foo() {
return "foo";
}
バージョン 4.3 では、value
アノテーション属性の channel
エイリアスが導入され、ソースコードの読みやすさが向上しました。また、ターゲット MessageChannel
Bean は、初期化段階ではなく、最初の receive()
呼び出しで提供された名前(outputChannelName
オプションで設定)によって SourcePollingChannelAdapter
で解決されます。これにより、「遅延バインディング」ロジックが可能になります。コンシューマーの観点からのターゲット MessageChannel
Bean が作成され、@InboundChannelAdapter
解析フェーズよりも少し遅れて登録されます。
最初の例では、デフォルトポーラーがアプリケーションコンテキストの他の場所で宣言されている必要があります。
@MessagingGateway
アノテーションの使用
@MessagingGateway
アノテーションを参照してください。
@IntegrationComponentScan
アノテーションの使用
標準の Spring Framework @ComponentScan
アノテーションは、ステレオタイプ @Component
アノテーションのインターフェースをスキャンしません。この制限を克服し、@MessagingGateway
(@MessagingGateway
アノテーションを参照)の構成を可能にするために、@IntegrationComponentScan
メカニズムを導入しました。このアノテーションは、@Configuration
アノテーションとともに配置し、basePackages
や basePackageClasses
などのスキャンオプションを定義するようにカスタマイズする必要があります。この場合、@MessagingGateway
のアノテーションが付けられたすべての検出されたインターフェースが解析され、GatewayProxyFactoryBean
インスタンスとして登録されます。他のすべてのクラスベースのコンポーネントは、標準の @ComponentScan
によって解析されます。
メッセージングメタアノテーション
バージョン 4.0 以降、すべてのメッセージングアノテーションをメタアノテーションとして構成でき、すべてのユーザー定義のメッセージングアノテーションは同じ属性を定義してデフォルト値をオーバーライドできます。さらに、次の例に示すように、メタアノテーションを階層的に構成できます。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput")
public @interface MyServiceActivator {
String[] adviceChain = { "annAdvice" };
}
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator
public @interface MyServiceActivator1 {
String inputChannel();
String outputChannel();
}
...
@MyServiceActivator1(inputChannel = "inputChannel", outputChannel = "outputChannel")
public Object service(Object payload) {
...
}
メタアノテーションを階層的に構成すると、ユーザーはさまざまな属性のデフォルトを設定でき、フレームワーク Java のユーザーアノテーションへの依存関係を分離して、ユーザークラスでの使用を回避できます。フレームワークが、フレームワークメタアノテーションを持つユーザーアノテーションを持つメソッドを見つけると、そのメソッドがフレームワークアノテーションで直接アノテーション付けされたかのように扱われます。
@Bean
メソッドのアノテーション
バージョン 4.0 以降では、@Configuration
クラスの @Bean
メソッド定義にメッセージングアノテーションを構成して、メソッドではなく Bean に基づいてメッセージエンドポイントを生成できます。@Bean
定義が「すぐに使える」 MessageHandler
インスタンス(AggregatingMessageHandler
、DefaultMessageSplitter
など)、Transformer
インスタンス(JsonToObjectTransformer
、ClaimCheckOutTransformer
など)、MessageSource
インスタンス(FileReadingMessageSource
、RedisStoreMessageSource
など)である場合に役立ちます。次の例は、@Bean
アノテーションでメッセージングアノテーションを使用する方法を示しています。
@Configuration
@EnableIntegration
public class MyFlowConfiguration {
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<String> consoleSource() {
return CharacterStreamReadingMessageSource.stdin();
}
@Bean
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
public ObjectToMapTransformer toMapTransformer() {
return new ObjectToMapTransformer();
}
@Bean
@ServiceActivator(inputChannel = "httpChannel")
public MessageHandler httpHandler() {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("https://foo/service");
handler.setExpectedResponseType(String.class);
handler.setOutputChannelName("outputChannel");
return handler;
}
@Bean
@ServiceActivator(inputChannel = "outputChannel")
public LoggingHandler loggingHandler() {
return new LoggingHandler("info");
}
}
バージョン 5.0 では、java.util.function.Supplier
を返す @InboundChannelAdapter
でアノテーションが付けられた @Bean
のサポートが導入されました。これにより、POJO または Message
のいずれかを生成できます。次の例は、その組み合わせの使用方法を示しています。
@Configuration
@EnableIntegration
public class MyFlowConfiguration {
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<String> pojoSupplier() {
return () -> "foo";
}
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<Message<String>> messageSupplier() {
return () -> new GenericMessage<>("foo");
}
}
メタアノテーションルールは @Bean
メソッドでも機能します(前述の @MyServiceActivator
アノテーションは @Bean
定義に適用できます)。
コンシューマー @Bean 定義でこれらのアノテーションを使用する場合、Bean 定義が適切な MessageHandler を返す場合(アノテーション型に応じて)、MessageHandler @Bean 定義自体に属性(outputChannel 、requiresReply 、order など)を設定する必要があります。次のアノテーション属性のみが使用されます: adviceChain 、autoStartup 、inputChannel 、phase 、poller 。他のすべての属性はハンドラー用です。 |
Bean 名は、次のアルゴリズムで生成されます。 |
MessageHandler
(MessageSource
)@Bean
は、@Bean
のメソッド名またはname
属性から独自の標準名を取得します。これは、@Bean
メソッドにメッセージングアノテーションがなかったかのように機能します。AbstractEndpoint
Bean 名は、[configurationComponentName].[methodName].[decapitalizedAnnotationClassShortName]
というパターンで生成されます。例: 前に示したconsoleSource()
定義のSourcePollingChannelAdapter
エンドポイントは、myFlowConfiguration.consoleSource.inboundChannelAdapter
という Bean 名を取得します。エンドポイント Bean 名も参照してください。
@Bean 定義でこれらのアノテーションを使用する場合、inputChannel は宣言された Bean を参照する必要があります。この場合、チャネルは自動的に宣言されません。 |
Java 構成では、
既存の Spring コンテナーロジックと一緒に、メッセージングエンドポイント Bean( |
アノテーション付きのブリッジを作成する
バージョン 4.0 以降、Java 構成は @BridgeFrom
および @BridgeTo
@Bean
メソッドのアノテーションを提供して、@Configuration
クラスの MessageChannel
Bean をマークします。これらは完全を期すために実際に存在し、BridgeHandler
とそのメッセージエンドポイント構成を宣言するための便利なメカニズムを提供します。
@Bean
public PollableChannel bridgeFromInput() {
return new QueueChannel();
}
@Bean
@BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000"))
public MessageChannel bridgeFromOutput() {
return new DirectChannel();
}
@Bean
public QueueChannel bridgeToOutput() {
return new QueueChannel();
}
@Bean
@BridgeTo("bridgeToOutput")
public MessageChannel bridgeToInput() {
return new DirectChannel();
}
これらのアノテーションは、メタアノテーションとしても使用できます。
アノテーション付きエンドポイントへのアドバイス
アノテーションを使用したエンドポイントへのアドバイスを参照してください。
メッセージマッピングのルールと規則
Spring Integration は、いくつかのデフォルトルールに依存して特定の規則を定義することにより、追加の構成を提供することなく、メッセージをメソッドとその引数にマッピングする柔軟な機能を実装しています。次のセクションの例は、ルールを明確にします。
サンプルシナリオ
次の例は、Map
または非 void 戻り型の Properties
オブジェクトではない単一のアノテーションなしパラメーター(オブジェクトまたはプリミティブ)を示しています。
public String doSomething(Object o);
入力パラメーターはメッセージのペイロードです。パラメーター型がメッセージペイロードと互換性がない場合は、Spring 3.0 が提供する変換サービスを使用してそれを変換しようとします。戻り値は、返されたメッセージのペイロードとして組み込まれます。
次の例は、Map
または Message
戻り値の型の Properties
ではない単一のアノテーションなしパラメーター(オブジェクトまたはプリミティブ)を示しています。
public Message doSomething(Object o);
入力パラメーターはメッセージのペイロードです。パラメーター型がメッセージペイロードと互換性がない場合は、Spring 3.0 が提供する変換サービスを使用してそれを変換しようとします。戻り値は、次の宛先に送信される新しく作成されたメッセージです。
次の例は、任意のオブジェクトまたはプリミティブな戻り型を持つメッセージ(またはそのサブクラスの 1 つ)である単一のパラメーターを示しています。
public int doSomething(Message msg);
入力パラメーター自体は Message
です。戻り値は、次の宛先に送信される Message
のペイロードになります。
次の例は、Message
(またはそのサブクラスの 1 つ)を戻り型として持つ Message
(またはそのサブクラスの 1 つ)である単一のパラメーターを示しています。
public Message doSomething(Message msg);
入力パラメーター自体は Message
です。戻り値は、新しく構築された Message
であり、次の宛先に送信されます。
次の例は、Map
または Properties
の単一のパラメーターと戻り値の型として Message
を示しています。
public Message doSomething(Map m);
これは少し興味深いです。最初は、メッセージヘッダーに直接簡単にマッピングできるように思われますが、常に Message
ペイロードが優先されます。つまり、Message
ペイロードの型が Map
である場合、この入力引数は Message
ペイロードを表します。ただし、Message
ペイロードの型が Map
でない場合、変換サービスはペイロードの変換を試行せず、入力引数はメッセージヘッダーにマップされます。
次の例は 2 つのパラメーターを示しています。1 つは Map
または Properties
オブジェクトではない任意の型(オブジェクトまたはプリミティブ)であり、もう 1 つは型 Map
または Properties
型(戻り値に関係なく)です。
public Message doSomething(Map h, <T> t);
この組み合わせには、そのうちの 1 つが Map
型である 2 つの入力パラメーターが含まれます。Map
以外のパラメーター(順序に関係なく)は Message
ペイロードにマッピングされ、Map
または Properties
(順序に関係なく)はメッセージヘッダーにマッピングされ、Message
構造と対話するための素晴らしい POJO 方法を提供します。
次の例は、パラメーターを示していません(戻り値に関係なく)。
public String doSomething();
このメッセージハンドラーメソッドは、このハンドラーが接続されている入力チャネルに送信されたメッセージに基づいて呼び出されます。ただし、Message
データはマップされないため、Message
はイベントまたはトリガーとして機能し、ハンドラーを呼び出します。出力は、前述の規則に従ってマッピングされます。
次の例は、パラメーターと void 戻り値を示しています。
public void soSomething();
この例は前の例と同じですが、出力は生成されません。
アノテーションベースのマッピング
アノテーションベースのマッピングは、メッセージをメソッドにマッピングするための最も安全で曖昧さの少ないアプローチです。次の例は、メソッドをヘッダーに明示的にマップする方法を示しています。
public String doSomething(@Payload String s, @Header("someheader") String b)
後で見ることができるように、アノテーションがない場合、このシグネチャーはあいまいな状態になります。ただし、最初の引数を Message
ペイロードに明示的にマッピングし、2 番目の引数を someheader
メッセージヘッダーの値に明示的にマッピングすることにより、あいまいさを回避します。
次の例は、前の例とほぼ同じです。
public String doSomething(@Payload String s, @RequestParam("something") String b)
@RequestMapping
またはその他の Spring Integration 以外のマッピングアノテーションは無関係であるため無視され、2 番目のパラメーターはマッピングされません。2 番目のパラメーターは簡単にペイロードにマッピングできますが、ペイロードは 1 つしか存在できません。アノテーションにより、このメソッドがあいまいになりません。
次の例は、アノテーションが意図を明確にしないとあいまいになる別の同様の方法を示しています。
public String foo(String s, @Header("foo") String b)
唯一の違いは、最初の引数が暗黙的にメッセージペイロードにマップされることです。
次の例は、3 つ以上の引数があるため、アノテーションなしでは間違いなく処理される別の署名を示しています。
public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)
引数の 2 つが Map
インスタンスであるため、この例は特に問題になります。ただし、アノテーションベースのマッピングを使用すると、あいまいさを簡単に回避できます。この例では、最初の引数はすべてのメッセージヘッダーにマッピングされ、2 番目と 3 番目の引数は "something" および "someotherthing" という名前のメッセージヘッダーの値にマッピングされます。ペイロードはどの引数にもマップされていません。
複雑なシナリオ
次の例では、複数のパラメーターを使用しています。
複数のパラメーターは、適切なマッピングの決定に関して多くのあいまいさを生み出す可能性があります。一般的なアドバイスは、メソッドパラメーターに @Payload
、@Header
、@Headers
アノテーションを付けることです。このセクションの例は、例外が発生する結果となるあいまいな条件を示しています。
public String doSomething(String s, int i)
2 つのパラメーターの重量は同じです。どれがペイロードであるかを判別する方法はありません。
次の例は、3 つのパラメーターのみがある同様の問題を示しています。
public String foo(String s, Map m, String b)
Map はメッセージヘッダーに簡単にマッピングできますが、2 つの String パラメーターをどうするかを決定する方法はありません。
次の例は、別のあいまいな方法を示しています。
public String foo(Map m, Map f)
1 つの Map
をメッセージペイロードに、もう 1 つをメッセージヘッダーにマッピングできると主張するかもしれませんが、順序に依存することはできません。
(Map、<T>)ではなく、アノテーションのないパラメーターを持つ複数のメソッド引数を持つメソッドシグネチャーは、あいまいな状態になり、例外をトリガーします。 |
次の一連の例はそれぞれ、あいまいさをもたらす複数のメソッドを示しています。
複数のメソッドを持つメッセージハンドラーは、前の例で説明したのと同じルールに基づいてマップされます。ただし、一部のシナリオは依然として混乱を招く可能性があります。
次の例は、正当な(マッピング可能かつ明確な)署名を持つ複数のメソッドを示しています。
public class Something {
public String doSomething(String str, Map m);
public String doSomething(Map m);
}
(メソッドの名前が同じでも、異なる名前でも違いはありません)。Message
は、どちらの方法にもマッピングできます。最初のメソッドは、メッセージペイロードを str
にマップでき、メッセージヘッダーを m
にマップできるときに呼び出されます。2 番目の方法は、メッセージヘッダーのみを m
にマッピングすることで候補にすることもできます。さらに悪いことに、両方のメソッドの名前は同じです。最初は、次の構成のためにあいまいに見える場合があります。
<int:service-activator input-channel="input" output-channel="output" method="doSomething">
<bean class="org.things.Something"/>
</int:service-activator>
マッピングは最初にペイロードに基づいており、次に他のすべてに基づいているため機能します。つまり、最初の引数をペイロードにマッピングできるメソッドは、他のすべてのメソッドよりも優先されます。
次に、真に曖昧な状態を生成する別の例を考えてみましょう。
public class Something {
public String doSomething(String str, Map m);
public String doSomething(String str);
}
どちらの方法にも、メッセージペイロードにマップできるシグネチャーがあります。彼らも同じ名前を持っています。このようなハンドラーメソッドは例外をトリガーします。ただし、メソッド名が異なる場合は、method
属性を使用してマッピングに影響を与えることができます(次の例に示す)。次の例は、2 つの異なるメソッド名を使用した同じ例を示しています。
public class Something {
public String doSomething(String str, Map m);
public String doSomethingElse(String str);
}
次の例は、method
属性を使用してマッピングを指示する方法を示しています。
<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse">
<bean class="org.bar.Foo"/>
</int:service-activator>
構成では doSomethingElse
メソッドを明示的にマップするため、あいまいさはなくなりました。