知識庫 / Spring RSS 訂閱

Spring 與 AMQP 遠程調用

Spring
HongKong
4
02:36 PM · Dec 06 ,2025

1. 概述

我們在上一篇系列文章中瞭解到,我們可以利用 Spring Remoting 以及相關的技術,在服務器和客户端之間通過 HTTP 渠道實現同步 遠程過程調用

在本篇文章中,我們將 探索 Spring RemotingAMQP 之上,從而實現通過一種本質上異步的媒介執行同步 RPC

2. 安裝 RabbitMQ

有多種與 AMQP 兼容的消息傳遞系統可供選擇,我們選擇 RabbitMQ,因為它是一個經過驗證的平台,並且完全支持 Spring——這兩個產品均由同一家公司(Pivotal)管理。

如果您不熟悉 AMQPRabbitMQ,您可以閲讀我們的快速介紹。

因此,第一步是安裝和啓動 RabbitMQ。安裝方法多種多樣,您可以選擇您喜歡的安裝方法,按照官方指南中的步驟進行 操作

3. Maven 依賴項

我們將設置服務器端和客户端 Spring Boot 應用程序,以演示 AMQP Remoting 的工作原理。 就像 Spring Boot 經常一樣,我們只需要選擇並導入正確的 starter 依賴項,就像這裏解釋的:

<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 導入classpath中的所有傳遞依賴,則會默認啓動它。

4. 服務器應用程序

4.1. 公開服務

如前文所述,我們將暴露一個 <em >CabBookingService</em>,它模擬了一個典型的遠程服務。

首先,聲明一個實現服務接口的 Bean。 這是實際執行服務器端服務調用的 Bean:

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

接下來,我們定義服務器將從中檢索調用的隊列。在這種情況下,只需為其指定一個名稱,並在構造函數中提供它即可:

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

正如我們之前文章已經知道的,Spring Remoting 的主要概念之一是 Service Exporter,該組件實際上收集來自某些源的調用請求——在本例中是RabbitMQ隊列——並調用服務實現的所需方法

在本例中,我們定義了一個AmqpInvokerServiceExporter,正如您所看到的,它需要對AmqpTemplate的引用。 AmqpTemplate類由Spring Framework提供,並以同樣的方式簡化了處理AMQP兼容的消息系統,就像JdbcTemplate使處理數據庫變得更容易。

由於它將被Spring Boot的自動配置模塊自動提供,因此我們不會顯式定義該AmqpTemplate Bean。

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

最後,我們需要定義一個負責從隊列中消費消息並轉發到指定監聽器 的 容器</em/>。

然後,我們將這個 容器</em/>連接到我們在上一步驟中創建的 服務出口</em/>,以便接收隊列中的消息。 此時,ConnectionFactory</em/> 同樣由 Spring Boot</em/> 提供,就像 AmqpTemplate</em/> 一樣。

@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;
}

關於 RabbitMQ 的主要概念,即 Exchange(交換器)和 Binding(綁定)的介紹,可參考 這裏

由於 Spring Boot 不會自動配置 AmqpTemplate,因此我們需要手動設置它,並指定一個 routing key。 在進行此操作時,我們需要仔細核實 routing keyexchange 是否與之前步驟中定義的 Exchange 匹配。

@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. 部署

對於客户端應用程序,必須正確選擇 <em >application.properties</em > 文件中的值。 在常見的配置中,這些值將與服務器端使用的值完全一致。

5.3. 運行示例

這段內容應該足以演示通過 RabbitMQ 進行遠程調用。接下來,啓動 RabbitMQ 服務器應用程序和調用遠程服務的客户端應用程序。

發生在其背後的過程是,AmqpProxyFactoryBean 將構建一個實現 CabBookingService 的代理。

當在該代理上調用一個方法時,它會在 RabbitMQ 中排隊一個消息,其中包含調用的所有參數以及用於返回結果的隊列名稱。

該消息由 AmqpInvokerServiceExporter 消費,它調用實際的實現。然後,它將結果收集到一個消息中,並將其放置在接收消息中指定的隊列名稱上。

AmqpProxyFactoryBean 接收到結果,並最終返回服務器端最初產生的該值。

6. 結論

在本文中,我們瞭解到如何使用 Spring Remoting 在消息系統之上提供 RPC。

對於主要場景,利用 RabbitMQ 的異步特性可能更合適,但對於一些特定的、有限的場景,同步調用可能更容易理解、更快、更簡單地開發。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.