ルーティングスリップ

バージョン 4.1 から、Spring Integration はルーティングスリップ (英語) エンタープライズ統合パターンの実装を提供します。outputChannel がエンドポイントに指定されていない場合、routingSlip メッセージヘッダーとして実装され、AbstractMessageProducingHandler インスタンスの次のチャネルを決定するために使用されます。このパターンは、メッセージフローを決定するために複数のルーターを構成することが困難になる複雑で動的な場合に役立ちます。output-channel を持たないエンドポイントにメッセージが到着すると、routingSlip が調べられて、メッセージが送信される次のチャネルが決定されます。ルーティングスリップがなくなると、通常の replyChannel 処理が再開されます。

ルーティングスリップの構成は、HeaderEnricher オプションとして提示されます。これは、次の例に示すように、path エントリを含むセミコロンで区切られたルーティングスリップです。

<util:properties id="properties">
    <beans:prop key="myRoutePath1">channel1</beans:prop>
    <beans:prop key="myRoutePath2">request.headers[myRoutingSlipChannel]</beans:prop>
</util:properties>

<context:property-placeholder properties-ref="properties"/>

<header-enricher input-channel="input" output-channel="process">
    <routing-slip
        value="${myRoutePath1}; @routingSlipRoutingPojo.get(request, reply);
               routingSlipRoutingStrategy; ${myRoutePath2}; finishChannel"/>
</header-enricher>

上記の例には次のものがあります。

  • ルーティングスリップ path のエントリを解決可能なキーとして指定できることを示すための <context:property-placeholder> 構成。

  • <header-enricher> <routing-slip> サブエレメントは、RoutingSlipHeaderValueMessageProcessor を HeaderEnricher ハンドラーに移入するために使用されます。

  • RoutingSlipHeaderValueMessageProcessor は、解決されたルーティングスリップ path エントリの String 配列を受け入れ、key として path を、routingSlipIndex として 0 を含む singletonMap を(processMessage() から)返します。

ルーティングスリップ path エントリには、MessageChannel Bean 名、RoutingSlipRouteStrategy Bean 名、および Spring 式(SpEL)を含めることができます。RoutingSlipHeaderValueMessageProcessor は、最初の processMessage 呼び出しで、各ルーティングスリップ path エントリを BeanFactory に対してチェックします。エントリ(アプリケーションコンテキストの Bean 名ではない)を ExpressionEvaluatingRoutingSlipRouteStrategy インスタンスに変換します。RoutingSlipRouteStrategy エントリは、null または空の String を返すまで複数回呼び出されます。

ルーティングスリップは getOutputChannel プロセスに関係しているため、リクエスト / 応答コンテキストがあります。RoutingSlipRouteStrategy は、requestMessage および reply オブジェクトを使用する次の outputChannel を決定するために導入されました。この戦略の実装は、アプリケーションコンテキストで Bean として登録する必要があり、その Bean 名はルーティングスリップ path で使用されます。ExpressionEvaluatingRoutingSlipRouteStrategy 実装が提供されます。SpEL 式を受け入れ、内部 ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply オブジェクトが評価コンテキストのルートオブジェクトとして使用されます。これは、各 ExpressionEvaluatingRoutingSlipRouteStrategy.getNextPath() 呼び出しの EvaluationContext 作成のオーバーヘッドを回避するためです。これは、Message<?> request と Object reply の 2 つのプロパティを持つ単純な Java Bean です。この式の実装では、SpEL(たとえば @routingSlipRoutingPojo.get(request, reply) および request.headers[myRoutingSlipChannel])を使用してルーティングスリップ path エントリを指定し、RoutingSlipRouteStrategy に Bean を定義しないようにすることができます。

requestMessage 引数は常に Message<?> です。コンテキストに応じて、応答オブジェクトは Message<?>AbstractIntegrationMessageBuilder、任意のアプリケーションドメインオブジェクト(たとえば、サービスアクティベータによって呼び出された POJO メソッドによって返される場合)です。最初の 2 つのケースでは、SpEL(または Java 実装)を使用すると、通常の Message プロパティ(payload および headers)が利用可能です。任意のドメインオブジェクトの場合、これらのプロパティは使用できません。このため、結果が次のパスの決定に使用される場合、POJO メソッドと一緒に回覧先を使用する場合は注意してください。
ルーティングスリップが分散環境に関係している場合、ルーティングスリップ path にインライン式を使用しないことをお勧めします。この推奨事項は、クロス JVM アプリケーションなどの分散環境、メッセージブローカー(AMQP サポートまたは JMS サポートなど)を介した request-reply の使用、または統合フローでの永続的な MessageStore (メッセージストア)の使用に適用されます。フレームワークは RoutingSlipHeaderValueMessageProcessor を使用して ExpressionEvaluatingRoutingSlipRouteStrategy オブジェクトに変換し、routingSlip メッセージヘッダーで使用されます。このクラスは Serializable ではないため(BeanFactory に依存するため、そうではありません)、Message 全体がシリアライズ不可能になり、分散操作では NotSerializableException になります。この制限を克服するには、ExpressionEvaluatingRoutingSlipRouteStrategy Bean を希望の SpEL に登録し、ルーティングスリップ path 構成でその Bean 名を使用します。

Java 構成の場合、次の例に示すように、RoutingSlipHeaderValueMessageProcessor インスタンスを HeaderEnricher Bean 定義に追加できます。

@Bean
@Transformer(inputChannel = "routingSlipHeaderChannel")
public HeaderEnricher headerEnricher() {
    return new HeaderEnricher(Collections.singletonMap(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
            new RoutingSlipHeaderValueMessageProcessor("myRoutePath1",
                                                       "@routingSlipRoutingPojo.get(request, reply)",
                                                       "routingSlipRoutingStrategy",
                                                       "request.headers[myRoutingSlipChannel]",
                                                       "finishChannel")));
}

エンドポイントが応答を生成し、outputChannel が定義されていない場合、ルーティングスリップアルゴリズムは次のように機能します。

  • routingSlipIndex は、ルーティングスリップ path リストから値を取得するために使用されます。

  • routingSlipIndex の値が String の場合、BeanFactory から Bean を取得するために使用されます。

  • 返された Bean が MessageChannel のインスタンスである場合、次の outputChannel として使用され、routingSlipIndex は応答メッセージヘッダーでインクリメントされます(ルーティングスリップ path エントリは変更されません)。

  • 返された Bean が RoutingSlipRouteStrategy のインスタンスであり、その getNextPath が空の String を返さない場合、その結果は次の outputChannel の Bean 名として使用されます。routingSlipIndex は変更されません。

  • RoutingSlipRouteStrategy.getNextPath が空の String または null を返す場合、routingSlipIndex はインクリメントされ、getOutputChannelFromRoutingSlip は次のルーティングスリップ path アイテムに対して再帰的に呼び出されます。

  • 次のルーティングスリップ path エントリが String でない場合、RoutingSlipRouteStrategy のインスタンスでなければなりません。

  • routingSlipIndex がルーティングスリップ path リストのサイズを超えると、アルゴリズムは標準 replyChannel ヘッダーのデフォルトの動作に移行します。