アノテーションサポート

メッセージエンドポイントを構成するための XML 名前空間のサポートに加えて、アノテーションも使用できます。まず、Spring Integration は、クラスレベルの @MessageEndpoint をステレオタイプアノテーションとして提供します。つまり、Spring の @Component アノテーションが付けられているため、Spring のコンポーネントスキャンによって Bean 定義として自動的に認識されます。

さらに重要なのは、さまざまなメソッドレベルのアノテーションです。それらは、アノテーション付きメソッドがメッセージを処理できることを示しています。次の例は、クラスレベルとメソッドレベルの両方のアノテーションを示しています。

@MessageEndpoint
public class FooService {

    @ServiceActivator
    public void processMessage(Message message) {
        ...
    }
}

メソッドがメッセージを「処理」することの正確な意味は、特定のアノテーションに依存します。Spring Integration で使用できるアノテーションは次のとおりです。

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 コンポーネント (AbstractEndpoint インスタンスおよび MessageHandler インスタンス (または受信チャネルアダプターの場合は MessageSource インスタンス)) と同じ Bean が作成されます。@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 は他のサービスでオートワイヤーできますが、通常は通常のオートワイヤー処理中に定義がまだ利用できないため、@Lazy アノテーションでマークを付ける必要があります。

@Autowired
@Lazy
@Qualifier("someChannel")
MessageChannel someChannel;
...

@Bean
Thing1 dependsOnSPCA(@Qualifier("someInboundAdapter") @Lazy SourcePollingChannelAdapter someInboundAdapter) {
    ...
}

バージョン 6.0 から、すべてのメッセージングアノテーションが @Repeatable になりました。そのため、同じ型のいくつかを同じサービスメソッドで宣言できます。これは、それらのアノテーションが繰り返されるのと同じ数のエンドポイントを作成するという意味です。

@Transformer(inputChannel = "inputChannel1", outputChannel = "outputChannel1")
@Transformer(inputChannel = "inputChannel2", outputChannel = "outputChannel2")
public String transform(String input) {
    return input.toUpperCase();
}

@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 アノテーションの属性(maxMessagesPerPollfixedDelayfixedRatecron)を構成できます。また、バージョン 5.1 以降、PollingConsumer 用の receiveTimeout オプションも提供されます。より多くのポーリングオプション(たとえば、transactionadvice-chainerror-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 によって解析されます。