1. 序章

この記事では、主に小さな実用的な例を通じて、 SpringIntegrationのコアコンセプトを紹介します。

Spring Integrationは、エンタープライズアーキテクチャ内のシステムとプロセスの相互接続性を大幅に強化できる多くの強力なコンポーネントを提供します。

これは、最も優れた最も人気のあるデザインパターンのいくつかを具体化しており、開発者が独自のパターンを作成することを回避するのに役立ちます。

このライブラリがエンタープライズアプリケーションを埋める特定のニーズと、その代替案のいくつかよりもなぜそれが推奨されるのかを見ていきます。 また、SpringIntegrationベースのアプリケーションの開発をさらに簡素化するために利用できるいくつかのツールについても見ていきます。

2. 設定

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-core</artifactId>
    <version>4.3.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-file</artifactId>
    <version>4.3.5.RELEASE</version>
</dependency>

最新バージョンのSpringIntegrationCoreおよびSpringIntegration FileSupportをMavenCentralからダウンロードできます。

3. メッセージングパターン

このライブラリの基本的なパターンの1つは、メッセージングです。 このパターンは、メッセージ(元のシステムまたはプロセスから、事前定義されたチャネルを介して1つまたは複数のシステムまたはプロセスに移動するデータの個別のペイロード)を中心にしています。

歴史的に、このパターンは、次のような方法で複数の異種システムを統合するための最も柔軟な方法として生まれました。

  • 統合に関与するシステムをほぼ完全に切り離します
  • 統合の参加者システムが、プロトコル、フォーマット、またはその他の実装の詳細の基礎となる相互に完全に依存しないようにします
  • 統合に関与するコンポーネントの開発と再利用を奨励します

4. メッセージ統合の実行

指定されたフォルダから別の設定されたフォルダにMPEGビデオファイルをコピーする基本的な例を考えてみましょう。

@Configuration
@EnableIntegration
public class BasicIntegrationConfig{
    public String INPUT_DIR = "the_source_dir";
    public String OUTPUT_DIR = "the_dest_dir";
    public String FILE_PATTERN = "*.mpeg";

    @Bean
    public MessageChannel fileChannel() {
        return new DirectChannel();
    }

    @Bean
    @InboundChannelAdapter(value = "fileChannel", poller = @Poller(fixedDelay = "1000"))
    public MessageSource<File> fileReadingMessageSource() {
        FileReadingMessageSource sourceReader= new FileReadingMessageSource();
        sourceReader.setDirectory(new File(INPUT_DIR));
        sourceReader.setFilter(new SimplePatternFileListFilter(FILE_PATTERN));
        return sourceReader;
    }

    @Bean
    @ServiceActivator(inputChannel= "fileChannel")
    public MessageHandler fileWritingMessageHandler() {
        FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(OUTPUT_DIR));
        handler.setFileExistsMode(FileExistsMode.REPLACE);
        handler.setExpectReply(false);
        return handler;
    }
}

上記のコードは、サービスアクティベーター、統合チャネル、およびインバウンドチャネルアダプターを構成します。

これらの各コンポーネントタイプについては、後ほど詳しく説明します。 @EnableIntegration アノテーションは、このクラスをSpringIntegration構成として指定します。

Spring統合アプリケーションコンテキストを開始しましょう。

public static void main(String... args) {
    AbstractApplicationContext context 
      = new AnnotationConfigApplicationContext(BasicIntegrationConfig.class);
    context.registerShutdownHook();
    
    Scanner scanner = new Scanner(System.in);
    System.out.print("Please enter q and press <enter> to exit the program: ");
    
    while (true) {
       String input = scanner.nextLine();
       if("q".equals(input.trim())) {
          break;
      }
    }
    System.exit(0);
}

上記の主な方法は、統合コンテキストを起動します。 また、コマンドラインからの「 q 」文字の入力を受け入れて、プログラムを終了します。 コンポーネントをさらに詳しく調べてみましょう。

5. Spring統合コンポーネント

5.1. メッセージ

org.springframework.integration.Message インターフェースは、Springメッセージを定義します。SpringIntegrationコンテキスト内のデータ転送の単位です。

public interface Message<T> {
    T getPayload();
    MessageHeaders getHeaders();
}

これは、2つの重要な要素へのアクセサーを定義します。

  • org.springframework.integration.MessageHeaders クラスで定義されているように、基本的にメタデータの送信に使用できるキー値コンテナーであるメッセージヘッダー
  • 転送する価値のある実際のデータであるメッセージペイロード—このユースケースでは、ビデオファイルがペイロードです

5.2. チャネル

Spring Integration(そして実際にはEAI)のチャネルは、統合アーキテクチャーの基本的な配管です。 これは、メッセージが1つのシステムから別のシステムに中継されるパイプです。

これは、統合システムまたはプロセスが他のシステムにメッセージをプッシュする(または他のシステムからメッセージを受信する)ことができる文字通りのパイプと考えることができます。

Spring Integrationのチャネルには、必要に応じてさまざまなフレーバーがあります。 これらは主に構成可能であり、カスタムコードなしですぐに使用できますが、カスタムニーズがある場合は、堅牢なフレームワークを利用できます。

ポイントツーポイント(P2P)チャネルは、システムまたはコンポーネント間に1対1の通信回線を確立するために使用されます。 1つのコンポーネントがチャネルにメッセージを公開して、別のコンポーネントがメッセージを取得できるようにします。 チャネルの両端に存在できるコンポーネントは1つだけです。

これまで見てきたように、チャネルの構成は、DirectChannelのインスタンスを返すのと同じくらい簡単です。

@Bean
public MessageChannel fileChannel1() {
    return new DirectChannel();
}

@Bean
public MessageChannel fileChannel2() {
    return new DirectChannel();
}

@Bean
public MessageChannel fileChannel3() {
    return new DirectChannel();
}

ここでは、それぞれのゲッターメソッドの名前で識別される3つの個別のチャネルを定義しました。

Publish-Subscribe(Pub-Sub)チャネルは、システムまたはコンポーネント間に1対多の通信回線を確立するために使用されます。 これにより、以前に作成した3つの直接チャネルすべてに公開できるようになります。

したがって、この例に従って、P2Pチャネルをpub-subチャネルに置き換えることができます。

@Bean
public MessageChannel pubSubFileChannel() {
    return new PublishSubscribeChannel();
}

@Bean
@InboundChannelAdapter(value = "pubSubFileChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<File> fileReadingMessageSource() {
    FileReadingMessageSource sourceReader = new FileReadingMessageSource();
    sourceReader.setDirectory(new File(INPUT_DIR));
    sourceReader.setFilter(new SimplePatternFileListFilter(FILE_PATTERN));
    return sourceReader;
}

これで、インバウンドチャネルアダプタをPub-Subチャネルに公開するように変換しました。 これにより、ソースフォルダーから読み取られているファイルを複数の宛先に送信できるようになります。

5.3. 橋

Spring Integrationのブリッジは、何らかの理由で直接接続できない場合に、2つのメッセージチャネルまたはアダプターを接続するために使用されます。

この場合、ブリッジを使用して、Pub-Subチャネルを3つの異なるP2Pチャネルに接続できます(P2PチャネルとPub-Subチャネルは直接接続できないため)。

@Bean
@BridgeFrom(value = "pubSubFileChannel")
public MessageChannel fileChannel1() {
    return new DirectChannel();
}

@Bean
@BridgeFrom(value = "pubSubFileChannel")
public MessageChannel fileChannel2() {
    return new DirectChannel();
}

@Bean
@BridgeFrom(value = "pubSubFileChannel")
public MessageChannel fileChannel3() {
    return new DirectChannel();
}

上記のBean構成は、pubSubFileChannelを3つのP2Pチャネルにブリッジします。 @BridgeFrom アノテーションは、ブリッジを定義するものであり、Pub-Subチャネルにサブスクライブする必要がある任意の数のチャネルに適用できます。

上記のコードは、「 pubSubFileChannelからfileChannel1、fileChannel2、および fileChannel3 へのブリッジを作成して、 pubSubFileChannel 3つのチャネルすべてに同時に供給することができます。」

5.4. Service Activator

Service Activatorは、特定のメソッドで@ServiceActivatorアノテーションを定義する任意のPOJOです。 これにより、インバウンドチャネルからメッセージを受信したときに、POJOで任意のメソッドを実行でき、アウトバウンドチャネルにメッセージを書き込むことができます。

この例では、サービスアクティベーターは、構成された入力チャネルからファイルを受信し、構成されたフォルダーに書き込みます。

5.5. アダプタ

アダプタは、システムまたはデータソースに「プラグイン」できるようにするエンタープライズ統合パターンベースのコンポーネントです。 壁のソケットや電子機器に差し込むことでわかるように、これはほとんど文字通りアダプターです。

これにより、データベース、FTPサーバー、JMS、AMQPなどのメッセージングシステム、Twitterなどのソーシャルネットワークなどの「ブラックボックス」システムへの再利用可能な接続が可能になります。 これらのシステムに接続する必要があるということは、アダプターが非常にポータブルで再利用可能であることを意味します(実際、アダプターの小さなカタログがあり、自由に利用でき、誰でもすぐに使用できます)。

アダプタは、インバウンドとアウトバウンドの2つの大きなカテゴリに分類されます。

サンプルシナリオで使用されているアダプターのコンテキストで、これらのカテゴリーを調べてみましょう。

インバウンドアダプタは、これまで見てきたように、外部システム(この場合はファイルシステムディレクトリ)からメッセージを取り込むために使用されます。

インバウンドアダプタの構成は次のとおりです。

  • Bean構成をアダプターとしてマークする@InboundChannelAdapterアノテーション—アダプターがメッセージ(この場合はMPEGファイル)をフィードするチャネルとpollerを構成します。アダプターが指定された間隔で構成済みフォルダーをポーリングするのに役立つコンポーネント
  • FileReadingMessageSourceを返す標準のSpringjava構成クラス、ファイルシステムのポーリングを処理するSpringIntegrationクラスの実装

アウトバウンドアダプタは、メッセージを外部に送信するために使用されます。 Spring Integrationは、さまざまな一般的なユースケース向けに、すぐに使用できるさまざまなアダプターをサポートしています。

6. 結論

ライブラリのJavaベースの構成と利用可能なコンポーネントの再利用性を示すSpringIntegrationの基本的なユースケースを検討しました。

Spring Integrationコードは、JavaSE内のスタンドアロンプロジェクトとして、またJakartaEE環境でより大きなものの一部としてデプロイできます。 エンタープライズサービスバス(ESB)のような他のEAI中心の製品やパターンと直接競合することはありませんが、ESBが解決するために構築された同じ問題の多くを解決するための実行可能で軽量な代替手段です。

この記事のソースコードは、Githubプロジェクトにあります。