フィルター

メッセージフィルターは、メッセージヘッダー値やメッセージコンテンツ自体などの条件に基づいて、Message を渡すかドロップするかを決定するために使用されます。メッセージフィルターはルーターに似ていますが、フィルターの入力チャネルから受信した各メッセージについて、同じメッセージがフィルターの出力チャネルに送信される場合と送信されない場合があります。ルーターとは異なり、メッセージを送信するメッセージチャネルに関する決定は行いませんが、メッセージを送信するかどうかのみを決定します。

このセクションの後半で説明するように、フィルターは破棄チャネルもサポートします。場合によっては、ブール条件に基づいて、非常に単純なルーター(または「スイッチ」)のロールを果たすことができます。

Spring Integration では、MessageSelector インターフェースの実装に委譲するメッセージエンドポイントとしてメッセージフィルターを構成できます。次のように、このインターフェース自体は非常にシンプルです。

public interface MessageSelector {

    boolean accept(Message<?> message);

}

MessageFilter コンストラクターは、次の例に示すように、セレクターインスタンスを受け入れます。

MessageFilter filter = new MessageFilter(someSelector);

Java、Groovy、Kotlin DSL を使用したフィルターの構成

Java DSL で提供される IntegrationFlowBuilder は、Groovy および Kotlin DSL のベースとしても使用され、filter() 演算子用のオーバーロードされたメソッドを多数提供しています。前述の MessageSelector 抽象化は、filter() 定義のラムダ式として使用できます。

  • Java DSL

  • Kotlin DSL

  • Groovy DSL

@Bean
public IntegrationFlow someFlow() {
    return f -> f
              .<String>filter((payload) -> !"junk".equals(payload));
}
@Bean
fun someFlow() =
    integrationFlow {
        filter<String> { it != "junk" }
    }
@Bean
someFlow() {
    integrationFlow {
        filter String, { it != 'junk' }
    }
}

DSL の詳細については、次の各章を参照してください。

XML を使用したフィルターの構成

名前空間と SpEL を組み合わせて、ごくわずかな Java コードで強力なフィルターを構成できます。

<filter> 要素を使用して、メッセージ選択エンドポイントを作成できます。input-channel および output-channel 属性に加えて、ref 属性が必要です。次の例に示すように、ref は MessageSelector 実装を指すことができます。

<int:filter input-channel="input" ref="selector" output-channel="output"/>

<bean id="selector" class="example.MessageSelectorImpl"/>

または、method 属性を追加できます。その場合、ref 属性は任意のオブジェクトを参照できます。参照されるメソッドは、受信メッセージの Message 型またはペイロード型のいずれかを予期する場合があります。メソッドはブール値を返す必要があります。メソッドが "true" を返す場合、メッセージは出力チャネルに送信されます。次の例は、method 属性を使用するフィルターを構成する方法を示しています。

<int:filter input-channel="input" output-channel="output"
    ref="exampleObject" method="someBooleanReturningMethod"/>

<bean id="exampleObject" class="example.SomeObject"/>

セレクターまたは適応された POJO メソッドが false を返す場合、拒否されたメッセージの処理を制御するための設定がいくつかあります。前述の例のように設定されている場合、デフォルトでは拒否されたメッセージは何も通知されずに破棄されます。拒否によってエラー状態が発生するようにしたい場合は、次の例のように throw-exception-on-rejection 属性を true に設定してください。

<int:filter input-channel="input" ref="selector"
    output-channel="output" throw-exception-on-rejection="true"/>

拒否されたメッセージを特定のチャネルにルーティングする場合は、次の例に示すように、その参照を discard-channel として提供します。

<int:filter input-channel="input" ref="selector"
    output-channel="output" discard-channel="rejectedMessages"/>

throwExceptionOnRejection == false が指定され、discardChannel が指定されていない場合、メッセージはサイレントにドロップされ、o.s.i.filter.MessageFilter インスタンスは、この破棄されたメッセージに関する警告ログメッセージ (バージョン 6.1 以降) を出力するだけです。ログに警告を表示せずにメッセージを削除するには、フィルター上で NullChannel を discardChannel として構成できます。フレームワークのゴールは、デフォルトで完全にサイレントにならないようにすることであり、それが望ましい動作である場合は、明示的なオプションの設定を必要とします。

アドバイスフィルターも参照してください。

メッセージフィルターは、通常、パブリッシュ / サブスクライブチャネルと組み合わせて使用されます。多くのフィルターエンドポイントが同じチャネルにサブスクライブされている可能性があり、メッセージを次のエンドポイント (サポートされている型 (サービスアクティベータなど) のいずれか) に渡すかどうかを決定します。これは、単一のポイントツーポイント入力チャネルと複数の出力チャネルを備えたメッセージルーターを使用する、より積極的なアプローチに代わるリアクティブ代替手段を提供します。

カスタムフィルターの実装が他の <filter> 定義で参照されている場合は、ref 属性を使用することをお勧めします。ただし、カスタムフィルターの実装が単一の <filter> 要素にスコープされている場合は、次の例に示すように、内部 Bean 定義を提供する必要があります。

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

SpEL サポートの導入により、Spring Integration は expression 属性をフィルター要素に追加しました。次の例に示すように、単純なフィルターで Java を完全に回避するために使用できます。

<int:filter input-channel="input" expression="payload.equals('nonsense')"/>

expression 属性の値として渡された文字列は、評価コンテキストで利用可能なメッセージとともに SpEL 式として評価されます。アプリケーションコンテキストのスコープに式の結果を含める必要がある場合は、次の例に示すように、SpEL リファレンスドキュメントで定義されている #{} 表記を使用できます。

<int:filter input-channel="input"
            expression="payload.matches(#{filterPatterns.nonsensePattern})"/>

式自体を動的にする必要がある場合は、"expression" サブ要素を使用できます。これにより、ExpressionSource のキーを使って式を解決するための間接的なレベルが提供されます。これは直接実装できる戦略インターフェースですが、Spring Integration で提供されているバージョンを利用することもできます。このバージョンは「リソースバンドル」から式を読み込み、指定秒数後に変更の有無を確認できます。以下の設定例でこれらすべてが実証されています。この例では、基になるファイルが変更された場合、式は 1 分以内に再読み込みされます。

<int:filter input-channel="input" output-channel="output">
    <int:expression key="filterPatterns.example" source="myExpressions"/>
</int:filter>

<beans:bean id="myExpressions"
    class="o.s.i.expression.ReloadableResourceBundleExpressionSource">
    <beans:property name="basename" value="config/integration/expressions"/>
    <beans:property name="cacheSeconds" value="60"/>
</beans:bean>

ExpressionSource Bean が expressionSource という名前である場合、<expression> 要素に source 属性を指定する必要はありません。ただし、上記の例では完全性を保つために source 属性を指定しています。

次の例に示すように、"config/integration/expressions.properties" ファイル(またはリソースバンドルがロードされる一般的な方法で解決されるロケール拡張機能を備えたより具体的なバージョン)には、キー / 値のペアを含めることができます。

filterPatterns.example=payload > 100
expression を属性またはサブ要素として使用するこれらの例はすべて、トランスフォーマー、ルーター、スプリッター、サービスアクティベータ、ヘッダーエンリッチャーの各要素にも適用できます。コンポーネント型のセマンティクスとロールは、メソッド呼び出しの戻り値の解釈と同様に、評価結果の解釈に影響を与えます。たとえば、式はルーターコンポーネントによってメッセージチャネル名として扱われる文字列を返す場合があります。ただし、メッセージをルートオブジェクトとして式を評価し、プレフィックス "@" が付加された Bean 名を解決するという基本的な機能は、Spring Integration 内のすべてのコア EIP コンポーネントで一貫しています。

アノテーション付きのフィルターの構成

次の例は、アノテーションを使用してフィルターを構成する方法を示しています。

public class PetFilter {
    ...
    @Filter  (1)
    public boolean dogsOnly(String input) {
        ...
    }
}
1 このメソッドがフィルターとして使用されることを示すアノテーション。このクラスをフィルターとして使用する場合は、指定する必要があります。

XML 要素によって提供されるすべての構成オプションは、@Filter アノテーションでも使用できます。

フィルターは、XML から明示的に参照するか、クラスで @MessageEndpoint アノテーションが定義されている場合、クラスパススキャンにより自動的に検出されます。