1. 概要

シリーズの前回の記事で、 Spring Remoting と関連テクノロジーを活用して、間のHTTPチャネル上で同期リモートプロシージャコールを有効にする方法を説明しました。サーバーとクライアント。

この記事では、AMQPに加えて Spring Remotingについて説明します。これにより、本質的に非同期のメディアを活用しながら同期RPCを実行できます

2. RabbitMQのインストール

使用できるAMQPと互換性のあるさまざまなメッセージングシステムがあります。実績のあるプラットフォームであり、 Spring – の両方で完全にサポートされているため、RabbitMQを選択します。製品は同じ会社(Pivotal)によって管理されています。

AMQPまたはRabbitMQに精通していない場合は、クイックイントロダクションを読むことができます。

したがって、最初のステップは、RabbitMQをインストールして起動することです。 インストールにはさまざまな方法があります。公式ガイドに記載されている手順に従って、お好みの方法を選択してください。

3. Mavenの依存関係

サーバーとクライアントのSpring Boot アプリケーションをセットアップして、 AMQP Remotingがどのように機能するかを示します。 Spring Boot でよくあることですが、ここで説明するように、正しいスターター依存関係を選択してインポートする必要があります

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

spring-boot-starter-tomcat は、組み込みの HTTP サーバーを必要としないため、明示的に除外しました。 Maven を許可すると、代わりに自動的に起動されます。クラスパス内のすべての推移的な依存関係をインポートします。

4. サーバーアプリケーション

4.1. サービスを公開する

以前の記事で示したように、リモートサービスの可能性をシミュレートするCabBookingServiceを公開します。

リモートで呼び出し可能にしたいサービスのインターフェースを実装するBeanを宣言することから始めましょう。これは、サーバー側で実際にサービス呼び出しを実行するBeanです。

@Bean 
CabBookingService bookingService() {
    return new CabBookingServiceImpl();
}

次に、サーバーが呼び出しを取得するキューを定義しましょう。この場合、名前を指定して、コンストラクターで指定するだけで十分です。

@Bean 
Queue queue() {
    return new Queue("remotingQueue");
}

以前の記事からすでに知っているように、 Spring Remotingの主要な概念の1つは、Service Exporter です。これは、実際に何らかのソースからの呼び出し要求を収集するコンポーネントです。この場合、 RabbitMQキュー─そしてサービス実装で目的のメソッドを呼び出します。

この場合、 AmqpInvokerServiceExporter を定義します。これは、ご覧のとおり、AmqpTemplateへの参照が必要です。 AmqpTemplateクラスはSpringFramework によって提供され、 JdbcTemplate と同じように、AMQP-互換メッセージングシステムの処理を容易にします。データベースを処理します。

このようなAmqpTemplate Beanは、 Spring Boot の自動構成モジュールによって自動的に提供されるため、明示的に定義しません。

@Bean AmqpInvokerServiceExporter exporter(
  CabBookingService implementation, AmqpTemplate template) {
 
    AmqpInvokerServiceExporter exporter = new AmqpInvokerServiceExporter();
    exporter.setServiceInterface(CabBookingService.class);
    exporter.setService(implementation);
    exporter.setAmqpTemplate(template);
    return exporter;
}

最後に、キューからのメッセージを消費し、指定されたリスナーに転送する責任があるコンテナを定義する必要があります

次に、このコンテナをサービスエクスポータに接続します。前の手順で作成したで、キューに入れられたメッセージを受信できるようにします。 ここで、 ConnectionFactory は、 AmqpTemplate と同じように、 Spring Bootによって自動的に提供されます。

@Bean 
SimpleMessageListenerContainer listener(
  ConnectionFactory facotry, 
  AmqpInvokerServiceExporter exporter, 
  Queue queue) {
 
    SimpleMessageListenerContainer container
     = new SimpleMessageListenerContainer(facotry);
    container.setMessageListener(exporter);
    container.setQueueNames(queue.getName());
    return container;
}

4.2. 構成

application.properties ファイルを設定して、Spring Bootが基本オブジェクトを構成できるようにすることを忘れないでください。 もちろん、パラメーターの値は、RabbitMQがインストールされている方法にも依存します。

たとえば、 RabbitMQ がこの例が実行されているのと同じマシンで実行されている場合、次の構成が適切な構成になる可能性があります。

spring.rabbitmq.dynamic=true
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.host=localhost

5. クライアントアプリケーション

5.1. リモートサービスを呼び出す

それでは、クライアントに取り組みましょう。 ここでも、呼び出しメッセージが書き込まれるキューを定義する必要があります。 クライアントとサーバーの両方が同じ名前を使用していることを再確認する必要があります。

@Bean 
Queue queue() {
    return new Queue("remotingQueue");
}

クライアント側では、サーバー側よりも少し複雑なセットアップが必要です。 実際、関連するBindingを使用してExchange定義する必要があります。

@Bean 
Exchange directExchange(Queue someQueue) {
    DirectExchange exchange = new DirectExchange("remoting.exchange");
    BindingBuilder
      .bind(someQueue)
      .to(exchange)
      .with("remoting.binding");
    return exchange;
}

ExchangesおよびBindingsとしてのRabbitMQの主要な概念に関する優れたイントロは、こちらで入手できます。

Spring BootAmqpTemplateを自動構成しないため、ar outingkeyを指定して自分で設定する必要があります。 その際、ルーティングキー交換が前の手順で交換を定義するために使用したものと一致することを再確認する必要があります。

@Bean RabbitTemplate amqpTemplate(ConnectionFactory factory) {
    RabbitTemplate template = new RabbitTemplate(factory);
    template.setRoutingKey("remoting.binding");
    template.setExchange("remoting.exchange");
    return template;
}

次に、他の Spring Remoting 実装で行ったように、リモートで公開されるサービスのローカルプロキシを生成するFactoryBeanを定義します。 ここではあまり凝ったことはありません。リモートサービスのインターフェイスを提供する必要があります。

@Bean AmqpProxyFactoryBean amqpFactoryBean(AmqpTemplate amqpTemplate) {
    AmqpProxyFactoryBean factoryBean = new AmqpProxyFactoryBean();
    factoryBean.setServiceInterface(CabBookingService.class);
    factoryBean.setAmqpTemplate(amqpTemplate);
    return factoryBean;
}

これで、リモートサービスをローカルBeanとして宣言されているかのように使用できます。

CabBookingService service = context.getBean(CabBookingService.class);
out.println(service.bookRide("13 Seagate Blvd, Key Largo, FL 33037"));

5.2. 設定

また、クライアントアプリケーションの場合、application.propertiesファイルの値を適切に選択する必要があります。 一般的な設定では、これらはサーバー側で使用されているものと完全に一致します。

5.3. 例を実行する

これは、RabbitMQを介したリモート呼び出しを示すのに十分なはずです。 次に、RabbitMQ、サーバーアプリケーション、およびリモートサービスを呼び出すクライアントアプリケーションを起動しましょう。

舞台裏で行われるのは、AmqpProxyFactoryBeanがCabBookingServiceを実装するプロキシを構築することです。

メソッドがそのプロキシで呼び出されると、 RabbitMQ にメッセージをキューに入れ、呼び出しのすべてのパラメーターと、結果を送り返すために使用されるキューの名前を指定します。

メッセージは、実際の実装を呼び出すAmqpInvokerServiceExporterから消費されます。 次に、結果をメッセージに収集し、着信メッセージで指定された名前のキューに配置します。

AmqpProxyFactoryBean は結果を受け取り、最後に、サーバー側で最初に生成された値を返します。

6. 結論

この記事では、 Spring Remoting を使用して、メッセージングシステム上にRPCを提供する方法を説明しました。

RabbitMQ の非同期性を活用することを好む主なシナリオに進む方法ではないかもしれませんが、一部の選択された限定されたシナリオでは、同期呼び出しが理解しやすく、開発が迅速かつ簡単になる場合があります。

いつものように、ソースはGitHubにあります。