メッセージ変換

Transformer

メッセージトランスフォーマーは、メッセージプロデューサーとメッセージコンシューマーの疎結合を可能にする上で非常に重要なロールを果たします。すべてのメッセージ生成コンポーネントに、次のコンシューマーがどの型を期待するかを知る必要はなく、それらのコンポーネント間にトランスフォーマーを追加できます。String を XML ドキュメントに変換するような汎用トランスフォーマーも非常に再利用可能です。

一部のシステムでは、標準的なデータモデル (英語) を提供するのが最善かもしれませんが、Spring Integration の一般的な哲学は、特定の形式を必要としないことです。むしろ、最大限の柔軟性を得るために、Spring Integration は、拡張のために可能な限り単純なモデルを提供することを目指しています。他のエンドポイント型と同様に、XML または Java アノテーションで宣言型構成を使用すると、単純な POJO をメッセージトランスフォーマーのロールに適合させることができます。この章の残りの部分では、これらの構成オプションについて説明します。

柔軟性を最大化するために、Spring は XML ベースのメッセージペイロードを必要としません。それでも、フレームワークは、XML ベースのペイロードを処理するための便利なトランスフォーマーを提供します。これが実際にアプリケーションにとって正しい選択である場合です。これらのトランスフォーマーの詳細については、XML サポート - XML ペイロードの処理を参照してください。

XML を使用した Transformer の構成

<transformer> 要素は、メッセージ変換エンドポイントを作成するために使用されます。input-channel および output-channel 属性に加えて、ref 属性が必要です。ref は、単一のメソッドで @Transformer アノテーションを含むオブジェクトを指す場合もあれば(アノテーション付きの Transformer の構成を参照)、method 属性で指定された明示的なメソッド名の値と組み合わせる場合もあります。

<int:transformer id="testTransformer" ref="testTransformerBean" input-channel="inChannel"
             method="transform" output-channel="outChannel"/>
<beans:bean id="testTransformerBean" class="org.foo.TestTransformer" />

通常、カスタムトランスフォーマハンドラーの実装を他の <transformer> 定義で再利用できる場合は、ref 属性を使用することをお勧めします。ただし、カスタムトランスフォーマーハンドラーの実装を <transformer> の単一の定義にスコープする必要がある場合、次の例に示すように、内部 Bean 定義を定義できます。

<int:transformer id="testTransformer" input-channel="inChannel" method="transform"
                output-channel="outChannel">
  <beans:bean class="org.foo.TestTransformer"/>
</transformer>
同じ <transformer> 構成で ref 属性と内部ハンドラー定義の両方を使用することは許可されません。曖昧な状態を作成し、例外がスローされるためです。
ref 属性が AbstractMessageProducingHandler を継承する Bean(フレームワーク自体によって提供されるトランスフォーマーなど)を参照する場合、出力チャネルをハンドラーに直接注入することにより、構成が最適化されます。この場合、各 ref は、個別の Bean インスタンス(または prototype -scoped Bean)にするか、内部 <bean/> 構成型を使用する必要があります。誤って複数の Bean から同じメッセージハンドラーを参照すると、構成例外が発生します。

POJO を使用する場合、変換に使用されるメソッドは、受信メッセージの Message 型またはペイロード型のいずれかを予期する場合があります。また、@Header および @Headers パラメーターアノテーションをそれぞれ使用して、メッセージヘッダー値を個別に、または完全なマップとして受け入れることもできます。メソッドの戻り値は任意の型にできます。戻り値自体が Message である場合、トランスフォーマーの出力チャネルに渡されます。

Spring Integration 2.0 以降、メッセージトランスフォーマーの変換メソッドは null を返すことができなくなりました。メッセージトランスフォーマは常に各ソースメッセージを有効なターゲットメッセージに変換する必要があるため、null を返すと例外が発生します。つまり、専用の <filter> オプションがあるため、メッセージトランスフォーマーをメッセージフィルターとして使用しないでください。ただし、この型の動作が必要な場合(コンポーネントが null を返す可能性があり、エラーとは見なされない場合)、サービスアクティベーターを使用できます。その requires-reply 値はデフォルトで false ですが、トランスフォーマーと同様に、true に設定して、null 戻り値に対して例外をスローすることができます。

Transformers と Spring 式言語 (SpEL)

ルーター、アグリゲーター、その他のコンポーネントと同様に、Spring Integration 2.0 以降、トランスフォーマーも変換ロジックが比較的単純な場合はいつでも SpEL サポートの恩恵を受けることができます。次の例は、SpEL 式の使用方法を示しています。

<int:transformer input-channel="inChannel"
	output-channel="outChannel"
	expression="payload.toUpperCase() + '- [' + T(System).currentTimeMillis() + ']'"/>

前の例では、カスタムトランスフォーマーを作成せずにペイロードを変換します。ペイロード(String と想定)は大文字で、現在のタイムスタンプと連結され、いくつかのフォーマットが適用されています。

共通 Transformers

Spring Integration は、いくつかのトランスフォーマー実装を提供します。

オブジェクトから文字列への Transformer

Object の toString() 表現を使用することはかなり一般的であるため、Spring Integration は ObjectToStringTransformer を提供し、その出力は String payload を持つ Message です。この String は、受信メッセージのペイロードで toString() 操作を呼び出した結果です。次の例は、オブジェクトから文字列への変換のインスタンスを宣言する方法を示しています。

<int:object-to-string-transformer input-channel="in" output-channel="out"/>

このトランスフォーマーの潜在的な用途は、file 名前空間の「送信チャネルアダプター」に任意のオブジェクトを送信することです。そのチャネルアダプターは、デフォルトで String、バイト配列、java.io.File ペイロードのみをサポートしますが、アダプターが必要な変換を処理する直前にこのトランスフォーマを追加します。toString() 呼び出しの結果がファイルに書き込みたいものである限り、うまく機能します。それ以外の場合は、前に示した汎用 'transformer' 要素を使用して、カスタム POJO ベースのトランスフォーマーを提供できます。

logging-channel-adapter はメッセージペイロードをログに記録できるため、デバッグ時には、このトランスフォーマーは通常必要ありません。詳細については、ワイヤータップを参照してください。

オブジェクトから文字列への変換は非常に簡単です。受信ペイロードで toString() を呼び出します。Spring Integration 3.0 以降、このルールには 2 つの例外があります。

  • ペイロードが char[] である場合、new String(payload) を呼び出します。

  • ペイロードが byte[] の場合、new String(payload, charset) を呼び出します。charset はデフォルトで UTF-8 です。charset は、トランスフォーマーに charset 属性を指定することにより変更できます。

より高度な処理(実行時の文字セットの動的な選択など)を行うには、次の例に示すように、代わりに SpEL 式ベースのトランスフォーマーを使用できます。

<int:transformer input-channel="in" output-channel="out"
       expression="new java.lang.String(payload, headers['myCharset']" />

Object をバイト配列に直列化する必要がある場合、またはバイト配列を Object に逆直列化する必要がある場合、Spring Integration は対称直列化トランスフォーマーを提供します。これらはデフォルトで標準の Java 直列化を使用しますが、serializer 属性と deserializer 属性をそれぞれ使用して、Spring 3.0 のシリアライザーまたはセシリアライザー戦略の実装を提供できます。次の例は、Spring のシリアライザーとデシリアライザーを使用する方法を示しています。

<int:payload-serializing-transformer input-channel="objectsIn" output-channel="bytesOut"/>

<int:payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"
    allow-list="com.mycom.*,com.yourcom.*"/>
信頼できないソースからデータをデシリアライズするときは、パッケージおよびクラスパターンの allow-list を追加することを検討する必要があります。デフォルトでは、すべてのクラスはデシリアライズされます。
Object -to- Map および Map -to- Object トランス

Spring Integration は、Object から Map へのトランスフォーマーと Map から Object へのトランスフォーマーも提供します。これらは、JSON を使用してオブジェクトグラフを直列化および逆直列化します。オブジェクト階層は、最もプリミティブな型(Stringint など)にイントロスペクトされます。この型へのパスは、変換された Map で key になる SpEL で記述されます。プリミティブ型が値になります。

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

public class Parent{
    private Child child;
    private String name; 
    // setters and getters are omitted
}

public class Child{
    private String name; 
    private List<String> nickNames;
    // setters and getters are omitted
}

前の例の 2 つのクラスは、次の Map に変換されます。

{person.name=George, person.child.name=Jenna, person.child.nickNames[0]=Jen ...}

JSON ベースの Map では、実際の型を共有せずにオブジェクト構造を記述できます。これにより、構造を維持している限り、オブジェクトグラフを異なる型のオブジェクトグラフに復元および再構築できます。

例: Map -to- Object トランスフォーマーを使用して、前述の構造を次のオブジェクトグラフに復元できます。

public class Father {
    private Kid child;
    private String name; 
    // setters and getters are omitted
}

public class Kid {
    private String name; 
    private List<String> nickNames;
    // setters and getters are omitted
}

「構造化された」マップを作成する必要がある場合は、flatten 属性を指定できます。デフォルトは "true" です。'false' に設定すると、構造は Map オブジェクトの Map になります。

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

public class Parent {
	private Child child;
	private String name;
	// setters and getters are omitted
}

public class Child {
	private String name;
	private List<String> nickNames;
	// setters and getters are omitted
}

前の例の 2 つのクラスは、次の Map に変換されます。

{name=George, child={name=Jenna, nickNames=[Bimbo, ...]}}

これらのトランスフォーマーを構成するために、Spring Integration は、次の例に示すように、Object-to-Map のネームスペースサポートを提供します。

<int:object-to-map-transformer input-channel="directInput" output-channel="output"/>

次のように、flatten 属性を false に設定することもできます。

<int:object-to-map-transformer input-channel="directInput" output-channel="output" flatten="false"/>

Spring Integration は、次の例に示すように、Map-to-Object のネームスペースサポートを提供します。

<int:map-to-object-transformer input-channel="input" 
                         output-channel="output" 
                          type="org.something.Person"/>

または、次の例に示すように、ref 属性とプロトタイプスコープの Bean を使用できます。

<int:map-to-object-transformer input-channel="inputA" 
                                output-channel="outputA" 
                                ref="person"/>
<bean id="person" class="org.something.Person" scope="prototype"/>
"ref" および "type" 属性は相互に排他的です。また、'ref' 属性を使用する場合、「プロトタイプ」スコープの Bean を指す必要があります。そうでない場合、BeanCreationException がスローされます。

バージョン 5.0 からは、ObjectToMapTransformer にカスタマイズされた JsonObjectMapper を提供できます。日付の特別なフォーマットまたは空のコレクション(およびその他の用途)の null が必要な場合。JsonObjectMapper 実装の詳細については、JSONTransformers を参照してください。

ストリームトランス

StreamTransformer は、InputStream ペイロードを byte[](または charset が提供されている場合は String)に変換します。

次の例は、XML で stream-transformer 要素を使用する方法を示しています。

<int:stream-transformer input-channel="directInput" output-channel="output"/> <!-- byte[] -->

<int:stream-transformer id="withCharset" charset="UTF-8"
    input-channel="charsetChannel" output-channel="output"/> <!-- String -->

次の例は、StreamTransformer クラスと @Transformer アノテーションを使用して、Java でストリームトランスフォーマーを構成する方法を示しています。

@Bean
@Transformer(inputChannel = "stream", outputChannel = "data")
public StreamTransformer streamToBytes() {
    return new StreamTransformer(); // transforms to byte[]
}

@Bean
@Transformer(inputChannel = "stream", outputChannel = "data")
public StreamTransformer streamToString() {
    return new StreamTransformer("UTF-8"); // transforms to String
}
JSONTransformers

Spring Integration は、Object-to-JSON および JSON-to-Object トランスフォーマーを提供します。次の例のペアは、XML で宣言する方法を示しています。

<int:object-to-json-transformer input-channel="objectMapperInput"/>
<int:json-to-object-transformer input-channel="objectMapperInput"
    type="foo.MyDomainObject"/>

デフォルトでは、前述のリストのトランスフォーマーはバニラ JsonObjectMapper を使用します。クラスパスからの実装に基づいています。次の例に示すように、適切なオプションを使用して、または必要なライブラリ(GSON など)に基づいて、独自のカスタム JsonObjectMapper 実装を提供できます。

<int:json-to-object-transformer input-channel="objectMapperInput"
    type="something.MyDomainObject" object-mapper="customObjectMapper"/>

バージョン 3.0 以降、object-mapper 属性は、新しいストラテジーインターフェースのインスタンス JsonObjectMapper を参照します。この抽象化により、JSON マッパーの複数の実装を使用できます。Jackson 2 [GitHub] (英語) をラップする実装が提供され、クラスパスでバージョンが検出されます。クラスはそれぞれ Jackson2JsonObjectMapper です。

FactoryBean またはファクトリメソッドを使用して、必要な特性を持つ JsonObjectMapper を作成することを検討できます。次の例は、そのようなファクトリの使用方法を示しています。

public class ObjectMapperFactory {

    public static Jackson2JsonObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        return new Jackson2JsonObjectMapper(mapper);
    }
}

次の例は、XML で同じことを行う方法を示しています

<bean id="customObjectMapper" class="something.ObjectMapperFactory"
            factory-method="getMapper"/>

バージョン 2.2 以降、object-to-json-transformer は、入力メッセージにまだヘッダーがない場合、デフォルトで content-type ヘッダーを application/json に設定します。

content-type ヘッダーを他の値に設定するか、既存のヘッダーを何らかの値(application/json を含む)で明示的に上書きする場合は、content-type 属性を使用します。ヘッダーの設定を抑制したい場合は、content-type 属性を空の文字列("")に設定します。そのようにすると、content-type ヘッダーのないメッセージが生成されます(そのようなヘッダーが入力メッセージに存在しない限り)。

バージョン 3.0 から、ObjectToJsonTransformer は、ソース型を反映するヘッダーをメッセージに追加します。同様に、JsonToObjectTransformer は JSON をオブジェクトに変換するときにこれらの型ヘッダーを使用できます。これらのヘッダーは AMQP アダプターにマップされるため、Spring-AMQP JsonMessageConverter (Javadoc) と完全に互換性があります。

これにより、次のフローが特別な構成なしで機能します。

  • …​→amqp-outbound-adapter---→

  • ---→amqp-inbound-adapter→json-to-object-transformer→…​

    発信アダプターが JsonMessageConverter で構成され、受信アダプターがデフォルトの SimpleMessageConverter を使用する場合。

  • …​→object-to-json-transformer→amqp-outbound-adapter---→

  • ---→amqp-inbound-adapter→…​

    発信アダプターが SimpleMessageConverter で構成され、受信アダプターがデフォルトの JsonMessageConverter を使用する場合。

  • …​→object-to-json-transformer→amqp-outbound-adapter---→

  • ---→amqp-inbound-adapter→json-to-object-transformer→

    両方のアダプターが SimpleMessageConverter で構成されている場合。

ヘッダーを使用して型を判別する場合、class 属性はヘッダーより優先されるため、class 属性を指定しないでください。

JSONTransformers に加えて、Spring Integration は式で使用するための組み込み #jsonPath SpEL 関数を提供します。詳細については、Spring 式言語 (SpEL) を参照してください。

バージョン 3.0 以降、Spring Integration は式で使用するための組み込み #xpath SpEL 関数も提供します。詳細については、# xpath SpEL 関数を参照してください。

バージョン 4.0 以降、ObjectToJsonTransformer は resultType プロパティをサポートし、ノード JSON 表現を指定します。結果のノードツリー表現は、提供された JsonObjectMapper の実装に依存します。デフォルトでは、ObjectToJsonTransformer は Jackson2JsonObjectMapper を使用し、オブジェクトの変換をノードツリーに ObjectMapper#valueToTree メソッドに委譲します。ノード JSON 表現は、ダウンストリームメッセージフローが JSON データのプロパティにアクセスする SpEL 式を使用する場合、JsonPropertyAccessor を使用する効率を提供します。詳細については、プロパティアクセサーを参照してください。

バージョン 5.1 から、resultType を BYTES として構成して、このデータ型で動作するダウンストリームハンドラーで作業する場合に便利な byte[] ペイロードを持つメッセージを生成できます。

バージョン 5.2 から、JsonToObjectTransformer を ResolvableType で構成して、ターゲット JSON プロセッサーでのデシリアライズ中にジェネリクスをサポートできます。また、このコンポーネントは、JsonHeaders.RESOLVABLE_TYPE または JsonHeaders.TYPE_ID の存在について最初にリクエストメッセージヘッダーを調べ、それ以外の場合は設定された型にフォールバックします。また、ObjectToJsonTransformer は、考えられるダウンストリームシナリオのリクエストメッセージペイロードに基づいて JsonHeaders.RESOLVABLE_TYPE ヘッダーを設定します。

バージョン 5.2.6 以降、JsonToObjectTransformer を valueTypeExpression とともに提供して、ペイロードの ResolvableType を解決し、リクエストメッセージに対して実行時に JSON から変換することができます。デフォルトでは、リクエストメッセージで JsonHeaders を調べます。この式が null または ResolvableType のビルドが ClassNotFoundException をスローした場合、トランスフォーマーは提供された targetType にフォールバックします。JsonHeaders には実際のクラス値がない可能性があるため、このロジックは式として存在しますが、一部の外部レジストリに従ってターゲットクラスにマップする必要がある一部の型 ID があります。

Apache AvroTransformers

バージョン 5.2 には、Apache Avro との間で変換するためのシンプルなトランスフォーマーが追加されました。

スキーマレジストリがないという点で、洗練されていません。トランスフォーマーは、Avro スキーマから生成された SpecificRecord 実装に組み込まれたスキーマを使用するだけです。

SimpleToAvroTransformer に送信されるメッセージには、SpecificRecord を実装するペイロードが必要です。トランスフォーマーは複数の型を処理できます。SimpleFromAvroTransformer は、デシリアライズするデフォルトの型として使用される SpecificRecord クラスで構成する必要があります。setTypeExpression メソッドを使用して、逆直列化する型を決定する SpEL 式を指定することもできます。デフォルトの SpEL 式は headers[avro_type] (AvroHeaders.TYPE)であり、デフォルトでは、SimpleToAvroTransformer によってソースクラスの完全修飾クラス名が設定されます。式が null を返す場合、defaultType が使用されます。

SimpleToAvroTransformer には setTypeExpression メソッドもあります。これにより、プロデューサーとコンシューマーの分離が可能になり、送信者はヘッダーを型を表すトークンに設定し、コンシューマーはそのトークンを型にマッピングできます。

アノテーション付きの Transformer の構成

@Transformer アノテーションは、Message 型またはメッセージペイロード型のいずれかを期待するメソッドに追加できます。戻り値は、<transformer> 要素を説明するセクションで前述したのとまったく同じ方法で処理されます。次の例は、@Transformer アノテーションを使用して String を Order に変換する方法を示しています。

@Transformer
Order generateOrder(String productId) {
    return new Order(productId);
}

Transformer メソッドは、Annotation Support でドキュメント化されているように、@Header および @Headers アノテーションも受け入れることができます。次の例は、@Header アノテーションの使用方法を示しています。

@Transformer
Order generateOrder(String productId, @Header("customerName") String customer) {
    return new Order(productId, customer);
}

ヘッダーフィルター

変換のユースケースは、いくつかのヘッダーを削除するだけの簡単な場合もあります。このような使用例のために、Spring Integration は、出力メッセージから削除する特定のヘッダー名を指定できるヘッダーフィルターを提供します(たとえば、セキュリティ上の理由からヘッダーを削除したり、一時的にのみ必要な値を削除したりします)。基本的に、ヘッダーフィルターはヘッダーエンリッチャーの反対です。後者はヘッダーエンリッチャーで説明されています。次の例では、ヘッダーフィルターを定義しています。

<int:header-filter input-channel="inputChannel"
		output-channel="outputChannel" header-names="lastName, state"/>

ご覧のとおり、ヘッダーフィルターの構成は非常に簡単です。これは、入力チャネルと出力チャネル、および header-names 属性を持つ一般的なエンドポイントです。この属性は、削除する必要があるヘッダーの名前 (複数の場合はコンマで区切る) を受け入れます。前の例では、'lastName' および 'state' という名前のヘッダーは送信メッセージに存在しません。

コーデックベースの Transformers

コーデックを参照してください。

コンテンツエンリッチャー

場合によっては、ターゲットシステムによって提供されたよりも多くの情報でリクエストを強化する必要があるかもしれません。データエンリッチャー (英語) パターンでは、さまざまなシナリオと、そのような要件に対処できるコンポーネント(エンリッチャー)について説明します。

Spring Integration Core モジュールには、2 つのエンリッチャーが含まれています。

また、3 つのアダプター固有のヘッダーエンリッチャーが含まれています。

これらのアダプターの詳細については、このリファレンスマニュアルのアダプター固有のセクションを参照してください。

式のサポートに関する詳細については、Spring 式言語 (SpEL) を参照してください。

ヘッダーエンリッチャー

メッセージにヘッダーを追加するだけで、ヘッダーがメッセージの内容によって動的に決定されない場合、トランスフォーマーのカスタム実装を参照するのはやり過ぎかもしれません。そのため、Spring Integration はヘッダー強化パターンのサポートを提供します。<header-enricher> 要素を通じて公開されます。次の例は、その使用方法を示しています。

<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="foo" value="123"/>
    <int:header name="bar" ref="someBean"/>
</int:header-enricher>

ヘッダーエンリッチャーは、次の例に示すように、既知のヘッダー名を設定するための有用なサブ要素も提供します。

<int:header-enricher input-channel="in" output-channel="out">
    <int:error-channel ref="applicationErrorChannel"/>
    <int:reply-channel ref="quoteReplyChannel"/>
    <int:correlation-id value="123"/>
    <int:priority value="HIGHEST"/>
    <routing-slip value="channel1; routingSlipRoutingStrategy; request.headers[myRoutingSlipChannel]"/>
    <int:header name="bar" ref="someBean"/>
</int:header-enricher>

上記の構成は、よく知られたヘッダー(errorChannelcorrelationIdpriorityreplyChannelrouting-slip など)について、ヘッダー 'name' と 'value' の両方を提供する必要がある一般的な <header> サブ要素を使用する代わりに、便利なサブ要素を使用できることを示していますこれらの値を直接設定します。

バージョン 4.1 以降、ヘッダーエンリッチャーは routing-slip サブ要素を提供します。詳細については、ルーティングスリップを参照してください。

POJO サポート

多くの場合、ヘッダー値は静的に定義できず、メッセージの一部のコンテンツに基づいて動的に決定する必要があります。そのため、ヘッダーエンリッチャーでは、ref および method 属性を使用して Bean 参照も指定できます。指定されたメソッドは、ヘッダー値を計算します。次の構成と、String を変更するメソッドを備えた Bean を検討してください。

<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="something" method="computeValue" ref="myBean"/>
</int:header-enricher>

<bean id="myBean" class="thing1.thing2.MyBean"/>
public class MyBean {

    public String computeValue(String payload){
        return payload.toUpperCase() + "_US";
    }
}

次の例に示すように、POJO を内部 Bean として構成することもできます。

<int:header-enricher  input-channel="inputChannel" output-channel="outputChannel">
    <int:header name="some_header">
        <bean class="org.MyEnricher"/>
    </int:header>
</int:header-enricher>

次の例に示すように、同様に Groovy スクリプトを指すことができます。

<int:header-enricher  input-channel="inputChannel" output-channel="outputChannel">
    <int:header name="some_header">
        <int-groovy:script location="org/SampleGroovyHeaderEnricher.groovy"/>
    </int:header>
</int:header-enricher>
SpEL サポート

Spring Integration 2.0 では、Spring 式言語 (SpEL) の便利な機能を導入して、さまざまなコンポーネントの構成を支援しました。ヘッダーエンリッチャーはその 1 つです。前に示した POJO の例をもう一度参照してください。ヘッダー値を決定するための計算ロジックはかなり単純であることがわかります。自然な質問は、「これを達成するためのさらに簡単な方法はありますか?」です。これが、SpEL が真の力を発揮する場所です。次の例について考えてみます。

<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="foo" expression="payload.toUpperCase() + '_US'"/>
</int:header-enricher>

このような単純なケースに SpEL を使用することで、アプリケーションコンテキストで個別のクラスを提供して構成する必要がなくなりました。必要なことは、有効な SpEL 式で expression 属性を構成することだけです。'payload' および 'headers' 変数は SpEL 評価コンテキストにバインドされており、受信メッセージへのフルアクセスを提供します。

Java 構成を使用したヘッダーエンリッチャーの構成

次の 2 つの例は、ヘッダーエンリッチャーに Java 構成を使用する方法を示しています。

@Bean
@Transformer(inputChannel = "enrichHeadersChannel", outputChannel = "emailChannel")
public HeaderEnricher enrichHeaders() {
    Map<String, ? extends HeaderValueMessageProcessor<?>> headersToAdd =
            Collections.singletonMap("emailUrl",
                      new StaticHeaderValueMessageProcessor<>(this.imapUrl));
    HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
    return enricher;
}

@Bean
@Transformer(inputChannel="enrichHeadersChannel", outputChannel="emailChannel")
public HeaderEnricher enrichHeaders() {
    Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<>();
    headersToAdd.put("emailUrl", new StaticHeaderValueMessageProcessor<String>(this.imapUrl));
    Expression expression = new SpelExpressionParser().parseExpression("payload.from[0].toString()");
    headersToAdd.put("from",
               new ExpressionEvaluatingHeaderValueMessageProcessor<>(expression, String.class));
    HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
    return enricher;
}

最初の例は、単一のリテラルヘッダーを追加します。2 番目の例では、リテラルヘッダーと SpEL 式に基づくヘッダーの 2 つのヘッダーを追加します。

Java DSL を使用したヘッダーエンリッチャーの構成

次の例は、ヘッダーエンリッチャーの Java DSL 設定を示しています。

@Bean
public IntegrationFlow enrichHeadersInFlow() {
    return f -> f
                ...
                .enrichHeaders(h -> h.header("emailUrl", this.emailUrl)
                                     .headerExpression("from", "payload.from[0].toString()"))
                .handle(...);
}
ヘッダーチャネルレジストリ

Spring Integration 3.0 以降、新しいサブエレメント <int:header-channels-to-string/> が利用可能です。属性はありません。この新しいサブ要素は、既存の replyChannel および errorChannel ヘッダー(MessageChannel の場合)を String に変換し、後で送信するかエラーを処理するときのために、後で解決するためにチャネルをレジストリに保存します。これは、たとえばメッセージをメッセージストアに直列化するとき、または JMS を介してメッセージを転送するときなど、ヘッダーが失われる可能性がある場合に役立ちます。ヘッダーがまだ存在しないか、MessageChannel でない場合、変更は行われません。

この機能を使用するには、HeaderChannelRegistry Bean が必要です。デフォルトでは、フレームワークはデフォルトの有効期限(60 秒)で DefaultHeaderChannelRegistry を作成します。この時間を過ぎると、チャネルはレジストリから削除されます。この動作を変更するには、integrationHeaderChannelRegistry の id で Bean を定義し、コンストラクター引数(ミリ秒単位)を使用して、必要なデフォルト遅延を構成します。

バージョン 4.1 以降、removeOnGet というプロパティを <bean/> 定義の true に設定でき、マッピングエントリは最初の使用時にすぐに削除されます。これは、大規模な環境で、リーパーが削除するのを待つのではなく、チャネルが 1 回だけ使用される場合に役立ちます。

HeaderChannelRegistry には、レジストリの現在のサイズを決定する size() メソッドがあります。runReaper() メソッドは、現在のスケジュールされたタスクをキャンセルし、リーパーをすぐに実行します。次に、タスクは現在の遅延に基づいて再度実行されるようにスケジュールされます。これらのメソッドは、レジストリへの参照を取得することで直接呼び出すことができます。または、たとえば次のコンテンツを含むメッセージをコントロールバスに送信することもできます。

"@integrationHeaderChannelRegistry.runReaper()"

このサブ要素は便利で、次の構成を指定するのと同等です。

<int:reply-channel
    expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.replyChannel)"
    overwrite="true" />
<int:error-channel
    expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.errorChannel)"
    overwrite="true" />

バージョン 4.1 以降、レジストリの構成済みリーパー遅延をオーバーライドして、リーパー遅延に関係なく、少なくとも指定された時間チャネルマッピングが保持されるようになりました。次の例は、その方法を示しています。

<int:header-enricher input-channel="inputTtl" output-channel="next">
    <int:header-channels-to-string time-to-live-expression="120000" />
</int:header-enricher>

<int:header-enricher input-channel="inputCustomTtl" output-channel="next">
    <int:header-channels-to-string
        time-to-live-expression="headers['channelTTL'] ?: 120000" />
</int:header-enricher>

最初の場合、すべてのヘッダーチャネルマッピングの有効期間は 2 分です。2 番目のケースでは、有効期間はメッセージヘッダーで指定され、Elvis 演算子を使用して、ヘッダーがない場合は 2 分間を使用します。

ペイロードエンリッチャー

特定の状況では、前述のヘッダーエンリッチャーでは不十分な場合があり、ペイロード自体に追加情報を追加する必要がある場合があります。例: Spring Integration メッセージングシステムに入るオーダーメッセージは、提供された顧客番号に基づいてオーダーの顧客を検索し、その情報で元のペイロードを充実させる必要があります。

Spring Integration 2.1 はペイロードエンリッチャーを導入しました。ペイロードエンリッチャーは、Message を公開されたリクエストチャネルに渡し、応答メッセージを予期するエンドポイントを定義します。次に、応答メッセージは、式を評価してターゲットペイロードを強化するためのルートオブジェクトになります。

ペイロードエンリッチャーは、enricher 要素を介して完全な XML 名前空間をサポートします。リクエストメッセージを送信するために、ペイロードエンリッチャーには、メッセージをリクエストチャネルにディスパッチできる request-channel 属性があります。

基本的に、リクエストチャネルを定義することにより、ペイロードエンリッチャーはゲートウェイとして機能し、リクエストチャネルに送信されるメッセージが返されるのを待ちます。エンリッチャーは、返信メッセージで提供されたデータでメッセージのペイロードを増やします。

リクエストチャネルにメッセージを送信する場合、request-payload-expression 属性を使用して元のペイロードのサブセットのみを送信するオプションもあります。

ペイロードの強化は、SpEL 式を使用して構成され、最大限の柔軟性を提供します。応答チャネルの Message からの直接値でペイロードを強化するだけでなく、SpEL 式を使用してそのメッセージからサブセットを抽出したり、追加のインライン変換を適用したりして、データをさらに操作できます。

ペイロードを静的な値で強化するだけでよい場合、request-channel 属性を指定する必要はありません。

エンリッチャーはトランスフォーマーの一種です。多くの場合、ペイロードリッチャーまたは汎用トランスフォーマー実装を使用して、メッセージペイロードに追加データを追加できます。Spring Integration が提供するすべての変換可能なコンポーネントに精通し、ビジネスケースに最も意味的に適合する実装を慎重に選択する必要があります。
構成

次の例は、ペイロードエンリッチャーで使用可能なすべての構成オプションを示しています。

<int:enricher request-channel=""                           (1)
              auto-startup="true"                          (2)
              id=""                                        (3)
              order=""                                     (4)
              output-channel=""                            (5)
              request-payload-expression=""                (6)
              reply-channel=""                             (7)
              error-channel=""                             (8)
              send-timeout=""                              (9)
              should-clone-payload="false">                (10)
    <int:poller></int:poller>                              (11)
    <int:property name="" expression="" null-result-expression="'Could not determine the name'"/>   (12)
    <int:property name="" value="23" type="java.lang.Integer" null-result-expression="'0'"/>
    <int:header name="" expression="" null-result-expression=""/>   (13)
    <int:header name="" value="" overwrite="" type="" null-result-expression=""/>
</int:enricher>
1 エンリッチメントに使用するデータを取得するためにメッセージが送信されるチャネル。オプション。
2 アプリケーションコンテキストの起動中にこのコンポーネントを起動する必要があるかどうかを示すライフサイクル属性。デフォルトは true です。オプション。
3 基礎となる Bean 定義の ID。EventDrivenConsumer または PollingConsumer のいずれかです。オプション。
4 このエンドポイントがチャンネルのサブスクライバーとして接続されている場合の呼び出しの順序を指定します。これは、そのチャネルが「フェイルオーバー」ディスパッチ戦略を使用している場合に特に重要です。このエンドポイント自体がキューを持つチャネルのポーリングコンシューマーである場合、効果はありません。オプション。
5 メッセージがこのエンドポイントによって処理された後に送信されるメッセージチャネルを識別します。オプション。
6 デフォルトでは、元のメッセージのペイロードが request-channel に送信されるペイロードとして使用されます。request-payload-expression 属性の値として SpEL 式を指定することにより、元のペイロードのサブセット、ヘッダー値、その他の解決可能な SpEL 式を、リクエストチャネルに送信されるペイロードの基礎として使用できます。式の評価では、メッセージ全体を「ルートオブジェクト」として使用できます。たとえば、次の SpEL 式(とりわけ)が可能です: payload.somethingheaders.somethingnew java.util.Date()'thing1' + 'thing2'
7 返信メッセージが期待されるチャネル。これはオプションです。通常、自動生成された一時的な応答チャネルで十分です。オプション。
8Exception が request-channel のダウンストリームに発生した場合、ErrorMessage が送信されるチャネル。これにより、濃縮に使用する代替オブジェクトを返すことができます。設定されていない場合、Exception が呼び出し元にスローされます。オプション。
9 チャネルがブロックする可能性がある場合、チャネルにメッセージを送信するときに待機する最大時間(ミリ秒)。例: キューチャネルは、最大容量に達した場合、スペースが使用可能になるまでブロックできます。内部的には、送信タイムアウトは MessagingTemplate で設定され、MessageChannel で送信操作を呼び出すときに最終的に適用されます。デフォルトでは、送信タイムアウトは "-1" に設定されており、実装によっては、MessageChannel での送信操作が無期限にブロックされる可能性があります。オプション。
10Cloneable を実装するペイロードを、強化データを取得するためにリクエストチャネルにメッセージを送信する前に複製する必要があるかどうかを示すブール値。クローンバージョンは、最終的な応答のターゲットペイロードとして使用されます。デフォルトは false です。オプション。
11 このエンドポイントがポーリングコンシューマーである場合、メッセージポーラーを設定できます。オプション。
12 各 property サブ要素は、プロパティの名前を提供します(必須の name 属性を介して)。そのプロパティは、ターゲットペイロードインスタンスで設定可能である必要があります。value または expression 属性の正確に 1 つも指定する必要があります。前者はリテラル値を設定し、後者は評価する SpEL 式用です。評価コンテキストのルートオブジェクトは、このエンリッチャーによって開始されたフローから返されたメッセージです。リクエストチャネルまたはアプリケーションコンテキストがない場合の入力メッセージです(@<beanName>.<beanProperty> SpEL 構文を使用)。バージョン 4.0 以降、value 属性を指定するときに、オプションの type 属性を指定することもできます。宛先が型付き setter メソッドの場合、フレームワークは、変換を処理するために値を適切に強制します(PropertyEditor である限り)。ただし、ターゲットペイロードが Map の場合、エントリには変換なしの値が入力されます。type 属性を使用すると、たとえば、数値を含む String をターゲットペイロードの Integer 値に変換できます。バージョン 4.1 以降、オプションの null-result-expression 属性を指定することもできます。enricher が null を返すと、それが評価され、代わりに評価の出力が返されます。
13 各 header サブ要素は、メッセージヘッダーの名前を提供します(必須の name 属性を使用)。value 属性または expression 属性のいずれか 1 つも指定する必要があります。前者はリテラル値を設定し、後者は SpEL 式を評価するためのものです。評価コンテキストのルートオブジェクトは、このエンリッチャーによって開始されたフローから返されたメッセージです。リクエストチャネルまたはアプリケーションコンテキストがない場合の入力メッセージ('@ <beanName>。<beanProperty>' SpEL 構文を使用)。<header-enricher> と同様に、<enricher> 要素の header 要素には type および overwrite 属性があることに注意してください。ただし、重要な違いは、<enricher> では、overwrite 属性がデフォルトで true であり、<enricher> 要素の <property> サブ要素と一致することです。バージョン 4.1 から、オプションの null-result-expression 属性も指定できます。enricher が null を返すと、評価され、代わりに評価の出力が返されます。
サンプル

このセクションには、さまざまな状況でペイロードエンリッチャーを使用するいくつかの例が含まれています。

ここに示すコードサンプルは、Spring Integration Samples プロジェクトの一部です。Spring Integration サンプルを参照してください。

次の例では、User オブジェクトが Message のペイロードとして渡されます。

<int:enricher id="findUserEnricher"
              input-channel="findUserEnricherChannel"
              request-channel="findUserServiceChannel">
    <int:property name="email"    expression="payload.email"/>
    <int:property name="password" expression="payload.password"/>
</int:enricher>

User にはいくつかのプロパティがありますが、username のみが最初に設定されます。エンリッチャーの request-channel 属性は、User を findUserServiceChannel に渡すように構成されています。

暗黙的に設定された reply-channel を介して、User オブジェクトが返され、property サブ要素を使用して、応答からプロパティが抽出され、元のペイロードを強化するために使用されます。

リクエストチャネルにデータのサブセットのみを渡す方法は?

request-payload-expression 属性を使用する場合、完全なメッセージではなくペイロードの単一のプロパティをリクエストチャネルに渡すことができます。次の例では、ユーザー名プロパティがリクエストチャネルに渡されます。

<int:enricher id="findUserByUsernameEnricher"
              input-channel="findUserByUsernameEnricherChannel"
              request-channel="findUserByUsernameServiceChannel"
              request-payload-expression="payload.username">
    <int:property name="email"    expression="payload.email"/>
    <int:property name="password" expression="payload.password"/>
</int:enricher>

ユーザー名のみが渡されますが、リクエストチャネルへの結果のメッセージには MessageHeaders の完全なセットが含まれることに留意してください。

コレクションデータで構成されるペイロードを強化する方法はありますか?

次の例では、User オブジェクトの代わりに、Map が渡されます。

<int:enricher id="findUserWithMapEnricher"
              input-channel="findUserWithMapEnricherChannel"
              request-channel="findUserByUsernameServiceChannel"
              request-payload-expression="payload.username">
    <int:property name="user" expression="payload"/>
</int:enricher>

Map には、username マップキーにユーザー名が含まれています。username のみがリクエストチャネルに渡されます。応答には、完全な User オブジェクトが含まれており、最終的に user キーの Map に追加されます。

リクエストチャネルを使用せずに静的情報でペイロードを強化する方法はありますか

次の例では、リクエストチャネルをまったく使用せず、メッセージのペイロードを静的な値で強化するだけです。

<int:enricher id="userEnricher"
              input-channel="input">
    <int:property name="user.updateDate" expression="new java.util.Date()"/>
    <int:property name="user.firstName" value="William"/>
    <int:property name="user.lastName"  value="Shakespeare"/>
    <int:property name="user.age"       value="42"/>
</int:enricher>

ここでは、「静的」という言葉が大まかに使用されていることに注意してください。これらの値を設定するために SpEL 式を引き続き使用できます。

クレームチェック

前のセクションでは、メッセージにデータが欠落している状況に対処するのに役立つコンテンツエンリッチャーコンポーネントをいくつか取り上げました。また、メッセージからデータ項目を削除できるコンテンツフィルタリングについても説明しました。ただし、データを一時的に非表示にする場合があります。例: 分散システムでは、非常に大きなペイロードを持つメッセージを受信する場合があります。一部の断続的なメッセージ処理ステップはこのペイロードへのアクセスを必要とせず、一部は特定のヘッダーへのアクセスのみを必要とする場合があるため、各処理ステップで大きなメッセージペイロードを運ぶとパフォーマンスが低下し、セキュリティリスクが発生し、デバッグが困難になる場合があります。

ライブラリ内のストア (英語) (またはクレームチェック)パターンは、データのある場所へのポインター(クレームチェック)のみを維持しながら、よく知られた場所にデータを格納できるメカニズムを記述します。そのポインターを新しいメッセージのペイロードとして渡すことができます。これにより、メッセージフロー内のコンポーネントは、必要に応じてすぐに実際のデータを取得できます。このアプローチは、メールボックスでクレームチェックを取得し、実際のバゲッジを請求するために郵便局に行く必要がある認証メールプロセスに非常に似ています。また、フライト後またはホテルでのバゲッジ受取所と同じ考えです。

Spring Integration は、2 種類のクレームチェックトランスフォーマーを提供します。

  • 受信クレームチェックトランス

  • 発信クレームチェックトランス

便利な名前空間ベースのメカニズムを使用して構成できます。

受信クレームチェックトランス

受信クレームチェックトランスフォーマーは、message-store 属性によって識別されるメッセージストアにメッセージを格納することにより、受信メッセージを変換します。次の例では、受信クレームチェックトランスを定義しています。

<int:claim-check-in id="checkin"
        input-channel="checkinChannel"
        message-store="testMessageStore"
        output-channel="output"/>

上記の構成では、input-channel で受信されたメッセージは、message-store 属性で識別され、生成された ID でインデックス付けされたメッセージストアに保持されます。その ID は、そのメッセージのクレームチェックです。クレームチェックは、output-channel に送信される新しい(変換された)メッセージのペイロードにもなります。

ここで、ある時点で実際のメッセージにアクセスする必要があると仮定します。メッセージストアに手動でアクセスしてメッセージの内容を取得するか、送信クレームチェックトランスフォーマーを使用してクレームチェックを実際のメッセージに変換する以外は同じアプローチ(トランスフォーマーを作成)を使用できます。

次のリストは、受信クレームチェックトランスの利用可能なすべてのパラメーターの概要を示しています。

<int:claim-check-in auto-startup="true"             (1)
                    id=""                           (2)
                    input-channel=""                (3)
                    message-store="messageStore"    (4)
                    order=""                        (5)
                    output-channel=""               (6)
                    send-timeout="">                (7)
    <int:poller></int:poller>                       (8)
</int:claim-check-in>
1 アプリケーションコンテキストの起動時にこのコンポーネントを起動する必要があるかどうかを示すライフサイクル属性。デフォルトは true です。この属性は、Chain 要素内では使用できません。オプション。
2 基礎となる Bean 定義(MessageTransformingHandler)を識別する ID。この属性は、Chain 要素内では使用できません。オプション。
3 このエンドポイントの受信メッセージチャネル。この属性は、Chain 要素内では使用できません。オプション。
4 このクレームチェックトランスによって使用される MessageStore への参照。指定しない場合、デフォルトの参照は messageStore という名前の Bean になります。オプション。
5 このエンドポイントがチャンネルのサブスクライバーとして接続されている場合の呼び出しの順序を指定します。これは、そのチャネルが failover ディスパッチ戦略を使用する場合に特に関連します。このエンドポイント自体がキューを持つチャネルのポーリングコンシューマーである場合、効果はありません。この属性は、Chain 要素内では使用できません。オプション。
6 このエンドポイントによって処理された後、メッセージが送信されるメッセージチャネルを識別します。この属性は、Chain 要素内では使用できません。オプション。
7 応答メッセージを出力チャネルに送信するときに待機する最大時間(ミリ秒単位)を指定します。デフォルトは -1 — 無期限にブロックします。この属性は、Chain 要素内では使用できません。オプション。
8 ポーラーを定義します。この要素は、Chain 要素内では使用できません。オプション。

発信クレームチェックトランス

送信クレームチェックトランスフォーマーを使用すると、クレームチェックペイロードを持つメッセージを、ペイロードとして元のコンテンツを持つメッセージに変換できます。

<int:claim-check-out id="checkout"
        input-channel="checkoutChannel"
        message-store="testMessageStore"
        output-channel="output"/>

上記の構成では、input-channel で受信したメッセージには、ペイロードとしてクレームチェックが必要です。発信クレームチェックトランスフォーマーは、提供されたクレームチェックによって識別されたメッセージをメッセージストアに照会することにより、元のペイロードを持つメッセージに変換します。次に、新しくチェックアウトしたメッセージを output-channel に送信します。

次のリストは、発信クレームチェックトランスの利用可能なすべてのパラメーターの概要を示しています。

<int:claim-check-out auto-startup="true"             (1)
                     id=""                           (2)
                     input-channel=""                (3)
                     message-store="messageStore"    (4)
                     order=""                        (5)
                     output-channel=""               (6)
                     remove-message="false"          (7)
                     send-timeout="">                (8)
    <int:poller></int:poller>                        (9)
</int:claim-check-out>
1 アプリケーションコンテキストの起動時にこのコンポーネントを起動する必要があるかどうかを示すライフサイクル属性。デフォルトは true です。この属性は、Chain 要素内では使用できません。オプション。
2 基礎となる Bean 定義(MessageTransformingHandler)を識別する ID。この属性は、Chain 要素内では使用できません。オプション。
3 このエンドポイントの受信メッセージチャネル。この属性は、Chain 要素内では使用できません。オプション。
4 このクレームチェックトランスによって使用される MessageStore への参照。指定しない場合、デフォルトの参照は messageStore という名前の Bean になります。オプション。
5 このエンドポイントがチャンネルのサブスクライバーとして接続されている場合の呼び出しの順序を指定します。これは、そのチャネルが failover ディスパッチ戦略を使用している場合に特に重要です。このエンドポイント自体がキューを持つチャネルのポーリングコンシューマーである場合、効果はありません。この属性は、Chain 要素内では使用できません。オプション。
6 このエンドポイントによって処理された後、メッセージが送信されるメッセージチャネルを識別します。この属性は、Chain 要素内では使用できません。オプション。
7true に設定すると、メッセージはこのトランスフォーマーによって MessageStore から削除されます。この設定は、メッセージを 1 回だけ「要求」できる場合に役立ちます。デフォルトは false です。オプション。
8 応答メッセージを出力チャネルに送信するときに待機する最大時間(ミリ秒単位)を指定します。デフォルトは -1 — 無期限にブロックします。この属性は、Chain 要素内では使用できません。オプション。
9 ポーラーを定義します。この要素は、Chain 要素内では使用できません。オプション。

クレーム 1 回

特定のメッセージを 1 回だけ要求する必要がある場合があります。類推として、飛行機の荷物を処理するプロセスを検討してください。出発時に荷物をチェックインし、到着時にそれを請求します。荷物を受け取ったら、最初にチェックインし直さなければ再度請求することはできません。そのような場合に対応するため、claim-check-out トランスフォーマーに remove-message ブール属性を導入しました。この属性は、デフォルトで false に設定されています。ただし、true に設定されている場合、要求されたメッセージは MessageStore から削除されるため、再度要求することはできません。

この機能は、特にメモリ内の Map ベースの SimpleMessageStore の場合、ストレージスペースの点で影響があり、メッセージを削除しないと最終的に OutOfMemoryException につながる可能性があります。複数のクレームが行われないと思われる場合は、remove-message 属性の値を true に設定することをお勧めします。次の例は、remove-message 属性の使用方法を示しています。

<int:claim-check-out id="checkout"
        input-channel="checkoutChannel"
        message-store="testMessageStore"
        output-channel="output"
        remove-message="true"/>

メッセージストアの言葉

クレームチェックの詳細については(それらが機能する限り)あまり気にしませんが、Spring Integration の実際のクレームチェック(ポインター)の現在の実装では、一意性を確保するために UUID を使用します。

org.springframework.integration.store.MessageStore は、メッセージを保存および取得するための戦略インターフェースです。Spring Integration は、2 つの便利な実装を提供します。

  • SimpleMessageStore: インメモリ、Map ベースの実装 (デフォルト、テストに適しています)

  • JdbcMessageStore: JDBC 上でリレーショナルデータベースを使用する実装

コーデック

Spring Integration のバージョン 4.2 は、Codec 抽象化を導入しました。コーデックは、byte[] との間でオブジェクトをエンコードおよびデコードします。Java 直列化の代替手段を提供します。1 つの利点は、通常、オブジェクトが Serializable を実装する必要がないことです。Kryo [GitHub] (英語) を使用して直列化する実装を 1 つ提供していますが、次のコンポーネントで使用する独自の実装を提供できます。

  • EncodingPayloadTransformer

  • DecodingTransformer

  • CodecMessageConverter

EncodingPayloadTransformer

このトランスフォーマーは、コーデックを使用してペイロードを byte[] にエンコードします。メッセージヘッダーには影響しません。

詳細については、Javadoc を参照してください。

DecodingTransformer

このトランスフォーマーは、コーデックを使用して byte[] をデコードします。オブジェクトのデコード先の Class (または Class に解決される式)で構成する必要があります。結果のオブジェクトが Message<?> の場合、受信ヘッダーは保持されません。

詳細については、Javadoc を参照してください。

CodecMessageConverter

特定のエンドポイント(TCP や Redis など)には、メッセージヘッダーの概念がありません。それらは MessageConverter の使用をサポートし、CodecMessageConverter は、送信のためにメッセージを byte[] との間で変換するために使用できます。

詳細については、Javadoc を参照してください。

Kryo

現在、これは Codec の唯一の実装であり、2 種類の Codec を提供します。

  • PojoCodec: トランスで使用

  • MessageCodecCodecMessageConverter で使用

フレームワークは、いくつかのカスタムシリアライザーを提供します。

  • FileSerializer

  • MessageHeadersSerializer

  • MutableMessageHeadersSerializer

最初のものは、FileKryoRegistrar で初期化することにより、PojoCodec で使用できます。2 番目と 3 番目は MessageCodec で使用され、MessageKryoRegistrar で初期化されます。

Kryo のカスタマイズ

デフォルトでは、Kryo は未知の Java 型を FieldSerializer に委譲します。Kryo は、StringCollectionMap とともに、各プリミティブ型のデフォルトのシリアライザーも登録します。FieldSerializer は、反射を使用してオブジェクトグラフをナビゲートします。より効率的なアプローチは、オブジェクトの構造を認識し、選択したプリミティブフィールドを直接直列化できるカスタムシリアライザーを実装することです。次の例は、そのようなシリアライザーを示しています。

public class AddressSerializer extends Serializer<Address> {

    @Override
    public void write(Kryo kryo, Output output, Address address) {
        output.writeString(address.getStreet());
        output.writeString(address.getCity());
        output.writeString(address.getCountry());
    }

    @Override
    public Address read(Kryo kryo, Input input, Class<Address> type) {
        return new Address(input.readString(), input.readString(), input.readString());
    }
}

Serializer インターフェースは KryoInputOutput を公開します。これにより、Kryo ドキュメント [GitHub] (英語) に従って、含まれるフィールドやその他の内部設定を完全に制御できます。

カスタムシリアライザーを登録するときは、登録 ID が必要です。登録 ID は任意です。ただし、この場合、分散アプリケーション全体の各 Kryo インスタンスは同じ ID を使用する必要があるため、ID を明示的に定義する必要があります。Kryo は小さな正の整数を推奨し、いくつかの ID(値 <10)を予約します。Spring Integration は現在、40, 41,, 42 を使用するようにデフォルト設定されています(前述のファイルおよびメッセージヘッダーシリアライザー用)。フレームワークを拡張できるように、60 から開始することをお勧めします。前述のレジストラを構成することにより、これらのフレームワークのデフォルトをオーバーライドできます。
カスタム Kryo シリアライザーの使用

カスタム直列化が必要な場合は、ネイティブ API を使用してカスタマイズを行う必要があるため、Kryo [GitHub] (英語) のドキュメントを参照してください。例については、MessageCodec [GitHub] (英語) の実装を参照してください。

KryoSerializable の実装

ドメインオブジェクトのソースコードへの書き込みアクセス権がある場合は、ここで説明するように KryoSerializable を実装できます。この場合、クラスは直列化メソッド自体を提供し、それ以上の構成は必要ありません。ただし、ベンチマークでは、カスタムシリアライザーを明示的に登録するほど効率的ではないことが示されています。次の例は、カスタム Kryo シリアライザーを示しています。

public class Address implements KryoSerializable {
    ...

    @Override
    public void write(Kryo kryo, Output output) {
        output.writeString(this.street);
        output.writeString(this.city);
        output.writeString(this.country);
    }

    @Override
    public void read(Kryo kryo, Input input) {
        this.street = input.readString();
        this.city = input.readString();
        this.country = input.readString();
    }
}

この手法を使用して、Kryo 以外の直列化ライブラリをラップすることもできます。

@DefaultSerializer アノテーションの使用

Kryo は、ここで説明するように、@DefaultSerializer アノテーションも提供します。

@DefaultSerializer(SomeClassSerializer.class)
public class SomeClass {
       // ...
}

ドメインオブジェクトへの書き込みアクセス権がある場合、これはカスタムシリアライザーを指定するより簡単なメソッドです。これは ID を使用してクラスを登録しないため、特定の状況ではこの手法が役に立たない可能性があることに注意してください。