1. 概述
在前文中我们探讨了如何通过 Spring Remoting 在 AMQP 队列这类异步通道上实现 RPC。其实,使用 JMS 也能达到相同效果。
本文将手把手教你如何用 Spring Remoting JMS 和 Apache ActiveMQ 作为消息中间件,搭建远程调用系统。
2. 启动 Apache ActiveMQ 代理
Apache ActiveMQ 是个开源消息代理,能让应用异步交换信息,完全兼容 Java Message Service API。
要跑通我们的示例,得先启动一个 ActiveMQ 实例。有几种方式可选:
- 按官方指南操作
- 嵌入到 Java 应用中
- 最简单的是用 Docker 一键启动(推荐):
docker run -p 61616:61616 -p 8161:8161 rmohr/activemq:5.14.3
启动后:
- 端口
8161
提供管理界面,可查看队列、客户端等信息 - JMS 客户端需通过
61616
端口连接代理收发消息
3. Maven 依赖
和之前的 Spring Remoting 文章一样,我们将搭建服务端和客户端两个 Spring Boot 应用来演示 JMS Remoting。
依赖选择要精准,参考最佳实践:
<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 相关 jar 进入类路径。这样 Spring Boot 就不会启动嵌入式 Web 服务器——毕竟我们根本用不到它。
4. 服务端应用
4.1. 暴露服务
服务端需要暴露 CabBookingService 供客户端调用。
第一步:声明服务接口的实现 Bean,这是真正执行业务逻辑的组件:
@Bean
CabBookingService bookingService() {
return new CabBookingServiceImpl();
}
接着定义服务端接收调用的队列,构造器中指定队列名:
@Bean
Queue queue() {
return new ActiveMQQueue("remotingQueue");
}
根据前文经验,Spring Remoting 的核心是 Service Exporter——它从消息源(这里是 ActiveMQ 队列)收集调用请求,并转发给服务实现。
对于 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.api
spring.activemq.broker-url
指向 AMQ 端口spring.activemq.packages.trusted
需要重点说明:
⚠️ 安全踩坑:从 5.12.2 版本开始,ActiveMQ 默认拒绝 ObjectMessage
类型消息(用于传输序列化 Java 对象),因为存在潜在安全风险。
解决方案:显式告诉 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
配置通常与服务端一致。
启动顺序很重要:
- 先启动 ApacheMQ
- 再启动服务端应用
- 最后启动客户端应用调用服务
6. 总结
本文展示了如何用 Spring Remoting 在 JMS 系统(如 AMQ)上实现 RPC。
Spring Remoting 再次证明:无论底层通道是什么,快速搭建异步调用就是这么简单粗暴。
完整代码请移步 GitHub。