1. 概述
我們在上一篇文章中瞭解到,Spring Remoting 可以通過異步通道作為 AMQP 隊列,提供 RPC 服務。然而,我們也可以使用 JMS 達到相同的效果。
在本篇文章中,我們將探討如何使用 Spring Remoting JMS 和 Apache ActiveMQ 作為消息中間件進行遠程調用。
2. 啓動 Apache ActiveMQ 代理服務器
Apache ActiveMQ 是一款 開源消息代理,它允許應用程序異步交換信息,並且完全兼容 Java 消息服務 API。
為了運行我們的實驗,我們首先需要設置一個運行的 ActiveMQ 實例。我們可以選擇以下幾種方式:按照 官方指南 中描述的步驟,將其嵌入到 Java 應用程序中,或者更簡單地使用以下命令啓動一個 Docker 容器:
docker run -p 61616:61616 -p 8161:8161 rmohr/activemq:5.14.3這將啓動一個 ActiveMQ 容器,通過其暴露端口 8161 上的一個簡單的管理 Web GUI,通過它可以檢查可用的隊列、連接的客户端和其他管理信息。 JMS 客户端需要使用端口 61616 與代理服務器連接並交換消息。
3. Maven 依賴
如前幾篇文章介紹的 Spring Remoting 一樣,我們將設置一個服務器和一個客户端 Spring Boot 應用程序,以演示 JMS Remoting 的工作原理。
如常,我們會仔細選擇 Spring Boot starter 依賴項,正如此處所述:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>我們明確排除了 spring-boot-starter-tomcat,以避免將 Tomcat 相關的文件放入類路徑中。
這反過來又將阻止 Spring Boot 的自動配置機制在應用程序啓動時啓動嵌入式 Web 服務器,因為我們不需要它。
4. 服務器應用程序
4.1. 暴露服務
我們將設置一個服務器應用程序,該應用程序會暴露 CabBookingService,客户端可以調用它。
第一步是聲明一個實現我們想要暴露給客户端接口的 Bean。 這是一個 Bean,它將在服務器端執行業務邏輯:
@Bean
CabBookingService bookingService() {
return new CabBookingServiceImpl();
}我們接下來定義服務器從哪個隊列檢索調用實例,並在構造函數中指定其名稱:
@Bean
Queue queue() {
return new ActiveMQQueue("remotingQueue");
}正如我們之前文章中所知,Spring Remoting 的主要概念之一是 Service Exporter,該組件負責收集來自某些源的調用請求,在本例中,是 ApacheMQ 隊列,並調用服務實現的所需方法。
為了與 JMS 配合使用,我們定義了 JmsInvokerServiceExporter:
@Bean
JmsInvokerServiceExporter exporter(CabBookingService implementation) {
JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter();
exporter.setServiceInterface(CabBookingService.class);
exporter.setService(implementation);
return exporter;
}最後,我們需要定義一個監聽器,負責消費消息。該監聽器作為 ApacheMQ 和 JmsInvokerServiceExporter 之間的橋樑,它會監聽隊列中可用的調用消息,將調用轉發給服務導出器,並序列化返回結果:
@Bean SimpleMessageListenerContainer listener(
ConnectionFactory factory,
JmsInvokerServiceExporter exporter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(factory);
container.setDestinationName("remotingQueue");
container.setConcurrentConsumers(1);
container.setMessageListener(exporter);
return container;
}4.2. 配置
請務必設置 application.properties 文件,以便 Spring Boot 可以配置一些基本對象,例如監聽器所需的 ConnectionFactory。
各個參數的值主要取決於 ApacheMQ 的安裝方式,以下配置對於我們在同一台機器上運行這些示例的 Docker 容器來説是一個合理的配置:
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.packages.trusted=org.springframework.remoting.support,java.lang,com.baeldung.apispring.activemq.broker-url 參數是指 AMQ 端口的引用。spring.activemq.packages.trusted 參數需要更深入的解釋。
從版本 5.12.2 開始,ActiveMQ 默認拒絕所有類型為 ObjectMessage 的消息,因為這些消息被認為可能成為某些上下文中的安全攻擊媒介。
無論如何,可以通過指示 AMQ 接受指定包中的序列化對象來實現。 org.springframework.remoting.support 包包含代表遠程方法調用及其結果的主要消息。
com.baeldung.api 包包含我們服務的參數和結果。 添加了 java.lang,因為表示預訂結果的對象引用一個 String,因此我們需要序列化它。
5. 客户端應用程序
5.1. 調用遠程服務
現在讓我們來處理客户端。同樣,我們需要定義調用消息將寫入的隊列。我們需要確認客户端和服務器都使用相同的名稱。
@Bean
Queue queue() {
return new ActiveMQQueue("remotingQueue");
}我們還需要設置一個導出器:
@Bean
FactoryBean invoker(ConnectionFactory factory, Queue queue) {
JmsInvokerProxyFactoryBean factoryBean = new JmsInvokerProxyFactoryBean();
factoryBean.setConnectionFactory(factory);
factoryBean.setServiceInterface(CabBookingService.class);
factoryBean.setQueue(queue);
return factoryBean;
}我們現在可以像已聲明為本地 Bean 一樣使用遠程服務:
CabBookingService service = context.getBean(CabBookingService.class);
out.println(service.bookRide("13 Seagate Blvd, Key Largo, FL 33037"));5.2. 運行示例
對於客户端應用程序,我們必須在 <application>.properties 文件中正確選擇值。 在典型的配置中,這些值將與服務器端使用的值完全一致。
這應該足以演示通過 Apache AMQ 進行遠程調用。 因此,我們首先啓動 ApacheMQ,然後是服務器應用程序,最後是調用遠程服務的客户端應用程序。
6. 結論
在本快速教程中,我們看到了如何使用 Spring Remoting 在 AMQ 消息隊列系統之上提供 RPC。
Spring Remoting 持續展示了無論底層通道如何,異步調用設置起來都非常簡單。