You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何理解Spring AMQP中的异步与同步?官方示例疑问解析

Spring AMQP HelloWorld示例中“异步”的理解

我正在研读Spring AMQP的官方HelloWorld示例项目及对应文档,该项目包含同步(sync)和异步(async)两个版本,以下为异步版本代码:

生产者配置

@Configuration
public class ProducerConfiguration {

  protected final String helloWorldQueueName = "hello.world.queue";

  @Bean
  public RabbitTemplate rabbitTemplate() {
    RabbitTemplate template = new RabbitTemplate(connectionFactory());
    template.setRoutingKey(this.helloWorldQueueName);

    return template;
  }

  @Bean
  public ConnectionFactory connectionFactory() {
    return new CachingConnectionFactory();
  }

  @Bean
  public ScheduledProducer scheduledProducer() {
    return new ScheduledProducer();
  }

  @Bean
  public BeanPostProcessor postProcessor() {
    return new ScheduledAnnotationBeanPostProcessor();
  }

  static class ScheduledProducer {

    @Autowired
    private volatile RabbitTemplate rabbitTemplate;

    private final AtomicInteger counter = new AtomicInteger();

    @Scheduled(fixedRate = 3000)
    public void sendMessage() {
      rabbitTemplate.convertAndSend("Hello World " + counter.incrementAndGet());
    }
  }
}

消费者配置

@Configuration
public class ConsumerConfiguration {

  protected final String helloWorldQueueName = "hello.world.queue";

  @Bean
  public ConnectionFactory connectionFactory() {
    return new CachingConnectionFactory();
  }

  @Bean
  public SimpleMessageListenerContainer listenerContainer() {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory());
    container.setQueueNames(this.helloWorldQueueName);
    container.setMessageListener(new MessageListenerAdapter(new HelloWorldHandler()));

    return container;
  }

  @Bean
  public RabbitTemplate rabbitTemplate() {
    RabbitTemplate template = new RabbitTemplate(connectionFactory());
    template.setRoutingKey(this.helloWorldQueueName);
    template.setDefaultReceiveQueue(this.helloWorldQueueName);

    return template;
  }

  @Bean
  public Queue helloWorldQueue() {
    return new Queue(this.helloWorldQueueName);
  }
}

HelloWorldHandler

public class HelloWorldHandler {

  public void handleMessage(String text) {
    System.out.println("Received: " + text);
  }
}

官方文档说明:

由于本示例展示异步消息接收,生产端被设计为持续发送消息(如果是同步版本的单次执行发消息模式,就无法明显体现这是消息驱动的消费者)。负责持续发送消息的组件定义在ProducerConfiguration的内部类中,配置为每3秒运行一次。

我的疑问:我无法理解这段代码中的“异步”体现在哪里,因为在我的认知中,基础的“同步模式”下,amqpTemplate.convertAndSend()和amqpTemplate.receiveAndConvert()这类操作本身就是RabbitMQ的异步动作,生产者和消费者在收发消息时都不会阻塞。那么,该示例中的异步是如何体现的?如何理解Spring AMQP语境下的异步与同步?


解答

Spring AMQP语境下的“同步”和“异步”,核心区别在于消费者获取消息的模式,而非RabbitMQ协议层面的异步特性:

1. 同步消费者(拉模式)

同步消费者是主动拉取消息:通过调用rabbitTemplate.receive()或rabbitTemplate.receiveAndConvert()方法,主动向队列请求消息。如果队列中没有消息,调用会阻塞(可设置超时时间),直到获取到消息或超时。这种模式下,消费者需要主动发起请求才能拿到消息,类似“轮询”逻辑。

2. 异步消费者(推模式)

异步消费者是被动接收推送:通过SimpleMessageListenerContainer(或现代版本的@RabbitListener注解)注册消息监听器,容器会在后台维护长连接,RabbitMQ服务器有消息时会主动推送给消费者,监听器的处理方法(比如示例中的handleMessage)会自动触发执行。消费者不需要主动轮询,完全是事件驱动的异步处理逻辑。

示例中的异步体现

示例的异步版本核心在消费者端:

  • 使用了SimpleMessageListenerContainer,这个容器会启动后台线程持续监听队列,一旦队列有消息,就自动调用HelloWorldHandler.handleMessage处理消息,整个过程不需要消费者主动发起拉取请求,是典型的推模式异步消费。
  • 生产者的定时发送是为了配合演示:因为异步消费者是持续监听的,只有持续产生消息,才能直观体现“消息驱动、自动触发处理”的异步特性;如果是同步版本的单次发消息,很难体现这种持续的被动接收逻辑。

纠正认知偏差

你提到的convertAndSend本身确实是异步的(生产者发送消息后无需等待消费者处理即可返回),但Spring AMQP所说的同步/异步,是针对消费者的消息获取方式,而非生产者的发送动作。同步版本的消费者会通过主动拉取的方式获取消息,而异步版本则是被动接收推送,这才是两者的核心差异。

内容的提问来源于stack exchange,提问作者Enfield Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:39:51