1. 概述

系列前文中,我们探讨了如何利用 Spring Remoting 及相关技术,在 HTTP 通道上实现服务器与客户端间的同步远程过程调用(RPC)。本文将深入 Spring RemotingAMQP 上的实现——这让我们能在异步消息媒介上执行同步 RPC,实现技术上的巧妙融合。

2. 安装 RabbitMQ

市面上有多种兼容 AMQP 的消息系统,我们选择 RabbitMQ 的理由很简单:

  • ✅ 成熟稳定的生产级平台
  • ✅ 被 Spring 完全支持(两者同属 Pivotal 公司)

若对 AMQPRabbitMQ 不熟悉,可先阅读我们的快速入门指南。安装步骤:

  1. 访问官方安装指南
  2. 根据操作系统选择安装方式(Docker/二进制包/包管理器)
  3. 启动服务(默认端口 5672)

⚠️ 确保服务运行后再进行后续操作

3. Maven 依赖

我们将搭建服务端和客户端 Spring Boot 应用演示 AMQP Remoting。依赖配置很简单,只需引入正确的 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 服务器
  • Spring Boot 自动配置会处理其他 AMQP 相关组件

4. 服务端应用

4.1. 暴露服务

与之前文章类似,我们暴露一个模拟租车服务的 CabBookingService。核心步骤:

1. 定义服务实现 Bean

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

2. 创建消息队列

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

3. 配置服务导出器
Spring Remoting 的核心是 Service Exporter,这里使用 AmqpInvokerServiceExporter

@Bean AmqpInvokerServiceExporter exporter(
  CabBookingService implementation, AmqpTemplate template) {
 
    AmqpInvokerServiceExporter exporter = new AmqpInvokerServiceExporter();
    exporter.setServiceInterface(CabBookingService.class);
    exporter.setService(implementation);
    exporter.setAmqpTemplate(template);
    return exporter;
}
  • AmqpTemplateSpring Boot 自动配置提供
  • 导出器负责从队列接收调用并执行服务方法

4. 配置消息监听容器
连接队列与导出器的关键组件:

@Bean 
SimpleMessageListenerContainer listener(
  ConnectionFactory facotry, 
  AmqpInvokerServiceExporter exporter, 
  Queue queue) {
 
    SimpleMessageListenerContainer container
     = new SimpleMessageListenerContainer(facotry);
    container.setMessageListener(exporter);
    container.setQueueNames(queue.getName());
    return container;
}
  • ConnectionFactory 同样由 Spring Boot 自动配置
  • 容器持续消费队列消息并转发给导出器

4.2. 配置文件

application.properties 中配置 RabbitMQ 连接参数(示例为本地默认配置):

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

⚠️ 生产环境请修改默认凭据!

5. 客户端应用

5.1. 调用远程服务

客户端配置稍复杂,需要额外定义交换器和绑定:

1. 定义队列(与服务端同名)

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

2. 配置交换器与绑定

@Bean 
Exchange directExchange(Queue someQueue) {
    DirectExchange exchange = new DirectExchange("remoting.exchange");
    BindingBuilder
      .bind(someQueue)
      .to(exchange)
      .with("remoting.binding");
    return exchange;
}
  • 交换器(Exchange)和绑定(Binding)是 RabbitMQ 核心概念
  • 官方教程 有详细解释

3. 配置 AmqpTemplate

@Bean RabbitTemplate amqpTemplate(ConnectionFactory factory) {
    RabbitTemplate template = new RabbitTemplate(factory);
    template.setRoutingKey("remoting.binding");
    template.setExchange("remoting.exchange");
    return template;
}
  • 路由键和交换器名称需与服务端绑定匹配

4. 创建服务代理

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

5. 使用远程服务(像本地 Bean 一样)

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

5.2. 配置文件

客户端 application.properties 通常与服务端配置一致:

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

5.3. 运行示例

执行流程解析:

  1. AmqpProxyFactoryBean 创建 CabBookingService 代理
  2. 调用代理方法时:
    • 将调用参数和返回队列名封装成消息
    • 发送到 RabbitMQ 队列
  3. 服务端 AmqpInvokerServiceExporter
    • 接收消息并调用实际服务
    • 将结果放入指定的返回队列
  4. 客户端代理接收结果并返回

💡 这种同步调用模型在异步消息系统上实现了 RPC 语义,但本质上还是基于消息传递。

6. 结论

本文展示了如何通过 Spring Remoting 在消息系统上实现 RPC。虽然这种用法不是主流(RabbitMQ 的异步特性通常更受青睐),但在特定场景下:

  • ✅ 需要同步调用语义
  • ✅ 希望利用现有消息基础设施
  • ✅ 团队熟悉 Spring Remoting 模型

这种方案能提供更直观的开发体验。完整源码可在 GitHub 获取。


原始标题:Spring Remoting with AMQP