Spring AMQP 最佳实践指南

目录

  1. Spring AMQP 概述

  2. 快速集成

  3. 核心概念

  4. 消息发送

  5. 消息接收

  6. 消息转换器

  7. 请求 / 回复模式

  8. Broker 配置

  9. 异常处理与重试

  10. 事务支持

  11. 监听器容器配置

  12. 容错与恢复(Resilience)

  13. 测试支持

  14. 完整 Demo 示例

  15. 组件开发示例

  16. 最佳实践清单


1. Spring AMQP 概述

Spring AMQP 是一个基于 AMQP(Advanced Message Queuing Protocol) 协议的消息中间件框架,提供简洁的 API 来发送和接收异步、可靠的消息。它是 Spring 生态的一部分,与 Spring Boot、Spring Integration 等项目无缝集成。

核心能力:

  • AmqpTemplate / RabbitTemplate:高层抽象,简化消息的发送与接收

  • @RabbitListener:注解驱动的消息驱动 POJO

  • 消息转换器:自动进行 Java 对象与 AMQP 消息体之间的序列化/反序列化

  • 连接管理:连接与 Channel 的缓存、自动恢复

  • 声明式配置:Exchange、Queue、Binding 的自动声明

  • 消息确认、事务、重试:可靠性保障机制

  • Micrometer 可观测性:指标与链路追踪

版本兼容性(3.0.x):

  • Java 17+

  • Spring Framework 6.0+

  • RabbitMQ amqp-client 5.7.0+


2. 快速集成

2.1 Maven 依赖

<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>3.0.4</version>
</dependency>

2.2 Gradle 依赖

implementation 'org.springframework.amqp:spring-rabbit:3.0.4'

2.3 Spring Boot 自动配置(推荐)

Spring Boot 自动配置 ConnectionFactoryRabbitTemplateRabbitAdmin 等基础设施 Bean。

application.yml:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    # 发布者确认
    publisher-confirm-type: correlated
    publisher-returns: true
    # 消费者
    listener:
      simple:
        concurrency: 3
        max-concurrency: 10
        acknowledge-mode: manual
        retry:
          enabled: true
          max-attempts: 3
          initial-interval: 1000ms

示例应用:

@SpringBootApplication
public class Application {
​
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
​
    @Bean
    public Queue myQueue() {
        return new Queue("myqueue");
    }
​
    @Bean
    public ApplicationRunner runner(RabbitTemplate template) {
        return args -> template.convertAndSend("myqueue", "Hello, World!");
    }
​
    @RabbitListener(queues = "myqueue")
    public void listen(String message) {
        System.out.println("Received: " + message);
    }
}

2.4 纯 Java 配置

@Configuration
public class RabbitConfiguration {
​
    @Bean
    public CachingConnectionFactory connectionFactory() {
        CachingConnectionFactory factory = new CachingConnectionFactory("localhost");
        factory.setUsername("guest");
        factory.setPassword("guest");
        factory.setVirtualHost("/");
        // 启用发布者确认
        factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
        factory.setPublisherReturns(true);
        return factory;
    }
​
    @Bean
    public RabbitAdmin amqpAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }
​
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        // 设置消息转换器
        template.setMessageConverter(jackson2MessageConverter());
        // 确认回调
        template.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                System.out.println("消息发送成功: " + correlationData);
            } else {
                System.err.println("消息发送失败: " + cause);
            }
        });
        // 返回回调
        template.setReturnsCallback(returned -> {
            System.err.println("消息被退回: " + returned.getMessage());
        });
        return template;
    }
​
    @Bean
    public Jackson2JsonMessageConverter jackson2MessageConverter() {
        return new Jackson2JsonMessageConverter();
    }
​
    @Bean
    public Queue myQueue() {
        return new Queue("myqueue", true); // 持久化队列
    }
}

2.5 XML 配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="
         http://www.springframework.org/schema/rabbit
         https://www.springframework.org/schema/rabbit/spring-rabbit.xsd
         http://www.springframework.org/schema/beans
         https://www.springframework.org/schema/beans/spring-beans.xsd">
​
    <rabbit:connection-factory id="connectionFactory" host="localhost"/>
​
    <rabbit:template id="amqpTemplate"
                     connection-factory="connectionFactory"/>
​
    <rabbit:admin connection-factory="connectionFactory"/>
​
    <rabbit:queue name="myqueue"/>
​
</beans>

3. 核心概念

3.1 AMQP 抽象

AMQP 协议的三大核心要素:

概念说明关键类
Exchange消息交换机,接收生产者消息并按路由规则分发到队列DirectExchange, TopicExchange, FanoutExchange, HeadersExchange
Queue消息队列,存储消息直到被消费者取走Queue, AnonymousQueue
Binding绑定关系,定义 Exchange 到 Queue 的路由规则(routing key)Binding
Message消息体,包含 body(字节数组)和 properties(消息属性)Message

Exchange 类型:

// Direct Exchange:精确匹配 routing key
new DirectExchange("order.exchange");
​
// Topic Exchange:通配符匹配 routing key(* 匹配一个词,# 匹配零个或多个词)
new TopicExchange("event.exchange");
​
// Fanout Exchange:广播到所有绑定队列,忽略 routing key
new FanoutExchange("broadcast.exchange");
​
// Headers Exchange:根据消息 headers 匹配
new HeadersExchange("header.exchange");

声明示例:

@Bean
public DirectExchange orderExchange() {
    return new DirectExchange("order.exchange", true, false);
}
​
@Bean
public Queue orderQueue() {
    return QueueBuilder.durable("order.queue")
            .withArgument("x-dead-letter-exchange", "dlx.exchange")
            .withArgument("x-dead-letter-routing-key", "dlx.routing.key")
            .build();
}
​
@Bean
public Binding orderBinding(DirectExchange orderExchange, Queue orderQueue) {
    return BindingBuilder.bind(orderQueue)
            .to(orderExchange)
            .with("order.created");
}

3.2 连接与资源管理

CachingConnectionFactory(核心连接工厂)
@Bean
public CachingConnectionFactory connectionFactory() {
    CachingConnectionFactory factory = new CachingConnectionFactory("localhost");
    factory.setUsername("guest");
    factory.setPassword("guest");
    factory.setVirtualHost("/");
    factory.setPort(5672);
​
    // Channel 缓存大小(默认 25)
    factory.setChannelCacheSize(50);
​
    // 连接缓存模式:CHANNEL(默认)/ CONNECTION
    factory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL);
​
    // 连接限制
    factory.setChannelCheckoutTimeout(1000); // Channel 获取超时(ms)
​
    // 发布者确认
    factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
    factory.setPublisherReturns(true);
​
    return factory;
}
SSL 配置
@Bean
public RabbitConnectionFactoryBean rabbitConnectionFactory() {
    RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
    factory.setUseSSL(true);
    factory.setSslAlgorithm("TLSv1.2");
    factory.setKeyStore("file:/path/to/keystore.jks");
    factory.setKeyStorePassphrase("password");
    factory.setTrustStore("file:/path/to/truststore.jks");
    factory.setTrustStorePassphrase("password");
    return factory;
}
​
@Bean
public CachingConnectionFactory connectionFactory(
        RabbitConnectionFactoryBean rabbitConnectionFactory) throws Exception {
    return new CachingConnectionFactory(rabbitConnectionFactory.getObject());
}
集群连接
// addresses 格式:host1:port1,host2:port2
@Bean
public CachingConnectionFactory connectionFactory() {
    CachingConnectionFactory factory = new CachingConnectionFactory();
    factory.setAddresses("rabbit1:5672,rabbit2:5672,rabbit3:5672");
    factory.setUsername("guest");
    factory.setPassword("guest");
    return factory;
}
​
// 使用 AddressResolver 动态发现
@Bean
public CachingConnectionFactory connectionFactory(AddressResolver addressResolver) {
    CachingConnectionFactory factory = new CachingConnectionFactory();
    factory.setAddressResolver(addressResolver);
    return factory;
}
RabbitMQ 自动连接/拓扑恢复
spring:
  rabbitmq:
    connection-timeout: 30000
    requested-heartbeat: 60s
    # 自动恢复(RabbitMQ 客户端 4.0+ 默认启用)
    # 以下参数可覆写默认恢复行为

3.3 AmqpTemplate / RabbitTemplate

RabbitTemplateAmqpTemplate 接口的核心实现,提供同步和异步消息操作。

添加重试能力
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    RabbitTemplate template = new RabbitTemplate(connectionFactory);
​
    // 配置重试模板
    RetryTemplate retryTemplate = RetryTemplate.builder()
            .maxAttempts(3)
            .fixedBackoff(1000) // 固定间隔 1s
            .retryOn(AmqpIOException.class)
            .build();
    template.setRetryTemplate(retryTemplate);
​
    return template;
}
异步发布 — 检测成功与失败
// 确认回调
template.setConfirmCallback((correlationData, ack, cause) -> {
    if (ack) {
        log.info("消息 {} 已确认", correlationData.getId());
    } else {
        log.error("消息 {} 发送失败: {}", correlationData.getId(), cause);
        // 可在此做补偿逻辑:重发、记录到数据库
    }
});
​
// 退回回调(消息无法路由到队列时触发)
template.setReturnsCallback(returned -> {
    Message message = returned.getMessage();
    String replyText = returned.getReplyText();
    String exchange = returned.getExchange();
    String routingKey = returned.getRoutingKey();
    log.error("消息被退回: replyText={}, exchange={}, routingKey={}",
            replyText, exchange, routingKey);
});
Scope 操作(声明式交换/队列绑定后发送)
// 使用 invoke 方法,在发送消息前确保交换和队列已声明
template.invoke(t -> {
    // 在此声明
    t.execute(channel -> {
        channel.exchangeDeclare("temp.exchange", "direct", true);
        channel.queueDeclare("temp.queue", true, false, false, null);
        channel.queueBind("temp.queue", "temp.exchange", "routing.key");
        return null;
    });
    // 然后发送
    t.convertAndSend("temp.exchange", "routing.key", payload);
    return null;
});

4. 消息发送

Message Builder API

// 方式一:MessageBuilder
Message message = MessageBuilder.withBody("Hello".getBytes())
        .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
        .setMessageId(UUID.randomUUID().toString())
        .setHeader("custom-header", "custom-value")
        .setPriority(5)
        .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
        .build();
template.send("my.exchange", "my.routing.key", message);
​
// 方式二:MessagePostProcessor
template.convertAndSend("my.exchange", "my.routing.key", payload, msg -> {
    msg.getMessageProperties().setHeader("trace-id", traceId());
    msg.getMessageProperties().setExpiration("60000"); // 60s TTL
    return msg;
});

批处理

// 发送批量消息
List<Message> messages = Arrays.asList(
    MessageBuilder.withBody("batch-1".getBytes()).build(),
    MessageBuilder.withBody("batch-2".getBytes()).build(),
    MessageBuilder.withBody("batch-3".getBytes()).build()
);
​
// BatchingStrategy 控制批次大小和缓冲时间
BatchingRabbitTemplate batchingTemplate = new BatchingRabbitTemplate(
        connectionFactory,
        new SimpleBatchingStrategy(100, 1024 * 1024, 5000) // 100条/1MB/5s
);
batchingTemplate.send("my.exchange", "my.routing.key", messages);

5. 消息接收

消费者轮询(Polling Consumer)

// 同步接收
Message msg = template.receive("my.queue", 3000); // 3s 超时
String body = (String) template.receiveAndConvert("my.queue", 3000);
​
// 支持超时和类型转换
Order order = (Order) template.receiveAndConvert("order.queue", 5000);

异步消费者 — @RabbitListener

@Component
public class OrderListener {
​
    @RabbitListener(queues = "order.queue")
    public void handleOrder(Order order) {
        log.info("收到订单: {}", order);
        processOrder(order);
    }
​
    // 手动确认模式
    @RabbitListener(queues = "order.queue", ackMode = "MANUAL")
    public void handleOrderManual(Order order, Channel channel,
                                  @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        try {
            processOrder(order);
            channel.basicAck(tag, false);
        } catch (Exception e) {
            channel.basicNack(tag, false, true); // requeue
        }
    }
​
    // 监听多个队列
    @RabbitListener(queues = {"order.created", "order.updated", "order.cancelled"})
    public void handleOrderEvents(OrderEvent event,
                                  @Header("event-type") String eventType) {
        log.info("事件 [{}]: {}", eventType, event);
    }
​
    // 批处理监听
    @RabbitListener(queues = "order.batch.queue", containerFactory = "batchContainerFactory")
    public void handleBatch(List<Order> orders) {
        log.info("批量处理 {} 条订单", orders.size());
        orders.forEach(this::processOrder);
    }
​
    // 异步返回
    @RabbitListener(queues = "rpc.queue")
    @SendTo("reply.queue") // 将返回值发送到 reply.queue
    public String handleRpc(String request) {
        return "Response for: " + request;
    }
}

容器工厂配置

@Configuration
public class ListenerConfig {
​
    // 常规容器工厂
    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setConcurrentConsumers(3);          // 初始并发消费者
        factory.setMaxConcurrentConsumers(10);       // 最大并发消费者
        factory.setPrefetchCount(50);                // 预取数量
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setDefaultRequeueRejected(false);    // 拒绝时不重新入队
        factory.setMessageConverter(jackson2MessageConverter());
        return factory;
    }
​
    // 批处理容器工厂
    @Bean
    public SimpleRabbitListenerContainerFactory batchContainerFactory(
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setBatchListener(true);             // 启用批处理
        factory.setBatchSize(50);                    // 批次大小
        factory.setConsumerBatchEnabled(true);       // 消费者端批次
        factory.setReceiveTimeout(5000L);            // 批次超时
        return factory;
    }
​
    @Bean
    public Jackson2JsonMessageConverter jackson2MessageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}

两种容器对比

特性SimpleMessageListenerContainerDirectMessageListenerContainer
并发模型多线程,每个消费者一个线程每个队列一个 Channel,单线程
适用场景事务、大量队列、需严格排序高吞吐、少量队列、低延迟
预取控制支持 prefetchCount支持 prefetchCount
事务支持
动态扩缩
使用方式默认容器需显式指定 containerFactory

6. 消息转换器

常用转换器一览

// 1. SimpleMessageConverter — 默认,处理 String、byte[]、Serializable
template.setMessageConverter(new SimpleMessageConverter());
​
// 2. Jackson2JsonMessageConverter — JSON 序列化(推荐)
Jackson2JsonMessageConverter jsonConverter = new Jackson2JsonMessageConverter();
// 支持类型安全反序列化
jsonConverter.setClassMapper(new DefaultJackson2JavaTypeMapper());
template.setMessageConverter(jsonConverter);
​
// 3. Jackson2XmlMessageConverter — XML 序列化
template.setMessageConverter(new Jackson2XmlMessageConverter());
​
// 4. MarshallingMessageConverter — 基于 Spring OXM
template.setMessageConverter(new MarshallingMessageConverter(jaxb2Marshaller()));
​
// 5. ContentTypeDelegatingMessageConverter — 根据 Content-Type 委托
ContentTypeDelegatingMessageConverter delegating = new ContentTypeDelegatingMessageConverter();
delegating.addDelegate("application/json", jsonConverter);
delegating.addDelegate("application/xml", xmlConverter);
delegating.addDelegate("text/plain", simpleConverter);
template.setMessageConverter(delegating);

类型安全的 JSON 转换

@RabbitListener(queues = "order.queue")
public void handleOrder(
        @Payload Order order,
        @Header(AmqpHeaders.RECEIVED_ROUTING_KEY) String routingKey) {
    // @Payload 配合 DefaultJackson2JavaTypeMapper 确保类型正确
}
​
// 自定义 ClassMapper:通过消息头指定类型
DefaultJackson2JavaTypeMapper typeMapper = new DefaultJackson2JavaTypeMapper();
typeMapper.setTypePrecedence(Jackson2JavaTypeMapper.TypePrecedence.TYPE_ID);
// 消息发送时自动设置 __TypeId__ header

消息属性转换器

// 自定义 MessagePropertiesConverter
// 可自定义 AMQP 消息属性与 Spring MessageProperties 的映射

7. 请求 / 回复模式

同步请求 / 回复

// 发送并等待回复
Object response = template.convertSendAndReceive(
        "rpc.exchange", "rpc.key", request);
// 默认超时 5s,可配置
template.setReplyTimeout(30000);

异步请求 / 回复 — AsyncRabbitTemplate

@Configuration
public class AsyncConfig {
​
    @Bean
    public AsyncRabbitTemplate asyncRabbitTemplate(
            ConnectionFactory connectionFactory) {
        // 方式一:使用固定回复队列
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        Queue replyQueue = new Queue("async.reply.queue");
        AsyncRabbitTemplate asyncTemplate = new AsyncRabbitTemplate(
                rabbitTemplate, new SimpleMessageListenerContainer(connectionFactory), replyQueue.getName());
        return asyncTemplate;
    }
}
​
// 使用
@Component
public class RpcClient {
​
    @Autowired
    private AsyncRabbitTemplate asyncTemplate;
​
    public CompletableFuture<String> callAsync(String request) {
        RabbitConverterFuture<String> future = asyncTemplate.convertSendAndReceiveAsType(
                "rpc.exchange", "rpc.key", request,
                new ParameterizedTypeReference<String>() {});
        return future.completable(); // 转换为 CompletableFuture
    }
}

服务端 — @RabbitListener + @SendTo

@RabbitListener(queues = "rpc.queue")
@SendTo("reply.to.queue")  // 自动将返回值发送到指定队列
public OrderResult processOrder(OrderRequest request) {
    return orderService.process(request);
}

RabbitMQ Direct Reply-to(零队列优化)

// 启用 Direct Reply-to,无需声明回复队列,性能更优
template.setUseDirectReplyToContainer(true);
template.setReplyAddress("amq.rabbitmq.reply-to"); // 伪队列名

8. Broker 配置

Builder API 声明

@Configuration
public class BrokerConfig {
​
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        RabbitAdmin admin = new RabbitAdmin(connectionFactory);
        admin.setAutoStartup(true); // 自动声明
        return admin;
    }
​
    // Exchange Builder
    @Bean
    public DirectExchange orderExchange() {
        return ExchangeBuilder.directExchange("order.exchange")
                .durable(true)
                .autoDelete(false)
                .delayed()
                .build();
    }
​
    // Queue Builder(带死信配置)
    @Bean
    public Queue orderQueue() {
        return QueueBuilder.durable("order.queue")
                .withArgument("x-dead-letter-exchange", "dlx.exchange")
                .withArgument("x-dead-letter-routing-key", "order.dead")
                .withArgument("x-message-ttl", 60000)        // 消息 TTL
                .withArgument("x-max-length", 10000)          // 最大长度
                .maxPriority(10)                               // 最大优先级
                .quorum()                                      // 仲裁队列
                .build();
    }
​
    // Binding Builder
    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(orderQueue())
                .to(orderExchange())
                .with("order.created");
    }
​
    // 延迟队列插件(需要安装 rabbitmq_delayed_message_exchange)
    @Bean
    public DirectExchange delayedExchange() {
        return ExchangeBuilder.directExchange("delayed.exchange")
                .delayed()
                .build();
    }
​
    // 发送延迟消息
    public void sendDelayed(Object payload, int delayMs) {
        template.convertAndSend("delayed.exchange", "delayed.key", payload, msg -> {
            msg.getMessageProperties().setDelay(delayMs);
            return msg;
        });
    }
​
    // AnonymousQueue(自动生成名称,连接断开自动删除)
    @Bean
    public Queue anonymousQueue() {
        return new AnonymousQueue();
    }
​
    // 条件声明
    @Bean
    public Declarables declarables() {
        return new Declarables(
            new DirectExchange("conditional.exchange"),
            new Queue("conditional.queue"),
            new Binding("conditional.queue", Binding.DestinationType.QUEUE,
                    "conditional.exchange", "routing.key", null)
        );
    }
}

Broker 事件监听器

@Component
public class BrokerEventListener implements ApplicationListener<BrokerEvent> {
​
    @Override
    public void onApplicationEvent(BrokerEvent event) {
        if (event instanceof BrokerAvailableEvent) {
            log.info("Broker 已可用");
        } else if (event instanceof BrokerUnavailableEvent) {
            log.warn("Broker 不可用");
        }
    }
​
    // 或通过 @EventListener
    @EventListener
    public void handleBrokerAvailable(BrokerAvailableEvent event) {
        log.info("Broker 可用");
    }
}

9. 异常处理与重试

重试策略配置

// 监听器级别重试
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
        ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
​
    // 使用 RetryTemplate
    RetryTemplate retryTemplate = RetryTemplate.builder()
            .maxAttempts(3)
            .exponentialBackoff(1000, 2.0, 10000)  // 指数退避
            .retryOn(AmqpRejectAndDontRequeueException.class) // 不重试的异常
            .build();
    factory.setRetryTemplate(retryTemplate);
​
    return factory;
}

死信队列与 RepublishMessageRecoverer

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
        ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
​
    // 重试耗尽后将消息重新发布到死信队列
    MessageRecoverer recoverer = new RepublishMessageRecoverer(
            rabbitTemplate(connectionFactory), "dlx.exchange", "dlx.routing.key");
    RetryTemplate retryTemplate = RetryTemplate.builder()
            .maxAttempts(3)
            .exponentialBackoff(1000, 2.0, 10000)
            .build();
    factory.setRetryTemplate(retryTemplate);
    factory.setRecoveryCallback(new RetryContextExhaustedMessageRecoverer(recoverer));
​
    return factory;
}

@RabbitListener 异常处理

@Component
public class ExceptionHandlingListener {
​
    @RabbitListener(queues = "order.queue")
    public void handleOrder(Order order) {
        try {
            processOrder(order);
        } catch (OrderValidationException e) {
            // 业务异常,不重试,直接拒绝
            throw new AmqpRejectAndDontRequeueException("订单校验失败", e);
        } catch (TemporaryException e) {
            // 临时异常,重试
            throw e;
        }
    }
​
    // 全局异常处理器
    @RabbitListener(queues = "order.queue", errorHandler = "myErrorHandler")
    public void handleWithErrorHandler(Order order) {
        processOrder(order);
    }
}
​
// 自定义 ErrorHandler
@Component("myErrorHandler")
public class CustomErrorHandler implements RabbitListenerErrorHandler {
​
    @Override
    public Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
                              ListenerExecutionFailedException exception) {
        log.error("消息处理失败: {}", new String(amqpMessage.getBody()), exception);
        // 返回 null 表示消费成功(丢弃消息)
        return null;
    }
}

10. 事务支持

// 1. 启用 RabbitTemplate 事务
template.setChannelTransacted(true);
​
// 2. 使用 RabbitTransactionManager
@Bean
public RabbitTransactionManager transactionManager(
        ConnectionFactory connectionFactory) {
    return new RabbitTransactionManager(connectionFactory);
}
​
// 3. @Transactional 声明式事务
@Transactional(transactionManager = "rabbitTransactionManager")
public void sendWithTransaction() {
    template.convertAndSend("exchange", "queue1", "message1");
    template.convertAndSend("exchange", "queue2", "message2");
    // 如果任一发送失败,两者都回滚
}
​
// 4. 监听器容器事务
@Bean
public SimpleRabbitListenerContainerFactory transactionalContainerFactory(
        ConnectionFactory connectionFactory,
        RabbitTransactionManager transactionManager) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setChannelTransacted(true);
    factory.setTransactionManager(transactionManager);
    return factory;
}
​
// 5. 条件回滚
@Transactional(transactionManager = "rabbitTransactionManager")
public void conditionalRollback() {
    template.convertAndSend("exchange", "queueA", "msgA");
    // 基于条件决定是否回滚
    if (shouldRollback()) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

11. 监听器容器配置

SimpleMessageListenerContainer 直接编程式

@Bean
public SimpleMessageListenerContainer messageListenerContainer(
        ConnectionFactory connectionFactory,
        MessageListenerAdapter listenerAdapter) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueueNames("order.queue", "event.queue");
    container.setMessageListener(listenerAdapter);
    container.setConcurrentConsumers(5);
    container.setMaxConcurrentConsumers(20);
    container.setPrefetchCount(100);
    container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
    container.setAutoStartup(true);
    return container;
}
​
// MessageListenerAdapter 适配 POJO
@Bean
public MessageListenerAdapter listenerAdapter(OrderProcessor processor) {
    MessageListenerAdapter adapter = new MessageListenerAdapter(processor);
    adapter.setDefaultListenerMethod("process");
    adapter.setMessageConverter(jackson2MessageConverter());
    return adapter;
}

DirectMessageListenerContainer

@Bean
public DirectRabbitListenerContainerFactory directContainerFactory(
        ConnectionFactory connectionFactory) {
    DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setConsumersPerQueue(5);       // 每个队列的消费者数
    factory.setPrefetchCount(100);
    return factory;
}
​
// 使用时指定
@RabbitListener(queues = "high.throughput.queue",
        containerFactory = "directContainerFactory")
public void handleHighThroughput(Message msg) {
    // 高吞吐场景
}

12. 容错与恢复(Resilience)

自动恢复机制

Spring AMQP 内置了从 Broker 故障中恢复的能力:

@Bean
public CachingConnectionFactory connectionFactory() {
    CachingConnectionFactory factory = new CachingConnectionFactory("localhost");
    // 连接恢复间隔
    factory.setRecoveryInterval(5000);
    return factory;
}

RabbitAdmin 自动声明

@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
    RabbitAdmin admin = new RabbitAdmin(connectionFactory);
    // Broker 恢复连接后自动重新声明 Exchange/Queue/Binding
    admin.setAutoStartup(true);
    return admin;
}

同步操作失败重试

// RabbitTemplate 层面自动重试
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    RabbitTemplate template = new RabbitTemplate(connectionFactory);
    RetryTemplate retryTemplate = RetryTemplate.builder()
            .maxAttempts(5)
            .exponentialBackoff(500, 2.0, 5000)
            .retryOn(AmqpConnectException.class)
            .build();
    template.setRetryTemplate(retryTemplate);
    return template;
}

异常分类

// 致命异常 — 不应重试
AmqpRejectAndDontRequeueException     // 拒绝且不重新入队
ImmediateAcknowledgeAmqpException      // 立即确认(丢弃)
MessageConversionException             // 消息转换失败
​
// 可重试异常 — 建议重试
AmqpConnectException                   // 连接异常
AmqpIOException                        // IO 异常
ListenerExecutionFailedException       // 监听器执行失败

13. 测试支持

@SpringRabbitTest

@SpringRabbitTest
@SpringBootTest
class OrderListenerTest {
​
    @Autowired
    private RabbitTemplate rabbitTemplate;
​
    @Autowired
    private RabbitListenerTestHarness harness;
​
    @Test
    void testOrderProcessing() throws InterruptedException {
        // 发送测试消息
        rabbitTemplate.convertAndSend("order.exchange", "order.created",
                new Order("test-order", 100));
​
        // 获取监听器 spy
        OrderListener listener = harness.getSpy("orderListener");
        // 验证
        verify(listener, timeout(5000)).handleOrder(any(Order.class));
    }
}

@RabbitListenerTest 与 RabbitListenerTestHarness

@SpringBootTest
class ListenerTest {
​
    @Autowired
    private RabbitListenerTestHarness harness;
​
    @Test
    void testCapture() {
        RabbitListenerTestHarness.InvocationData invocationData =
                harness.getNextInvocationDataFor("myListener", 10, TimeUnit.SECONDS);
​
        assertNotNull(invocationData);
        assertEquals("expected-payload", invocationData.getArguments()[0]);
    }
}

TestRabbitTemplate

@Test
void testWithTestTemplate() {
    TestRabbitTemplate template = new TestRabbitTemplate(connectionFactory);
    template.convertAndSend("order.exchange", "order.created", testOrder);
    // 等待处理并通过模板验证状态
}

JUnit5 条件

@RabbitAvailable  // Broker 可用时才执行
@SpringBootTest
class IntegrationTest {
​
    @Test
    void testWithBroker() {
        // 仅在 RabbitMQ 可用时运行
    }
}
​
@LongRunning  // 长时测试标记
@SpringBootTest
class LongRunningTest {
​
    @Test
    void testLongRunning() {
        // 可能耗时的集成测试
    }
}

14. 完整 Demo 示例

14.1 Hello World — 同步版

public class HelloWorldSync {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
        AmqpAdmin admin = new RabbitAdmin(connectionFactory);
        admin.declareQueue(new Queue("myqueue"));
​
        AmqpTemplate template = new RabbitTemplate(connectionFactory);
        template.convertAndSend("myqueue", "foo");
​
        String result = (String) template.receiveAndConvert("myqueue");
        System.out.println("Received: " + result); // Received: foo
    }
}

14.2 Hello World — 异步版(Spring Boot)

@SpringBootApplication
public class HelloWorldAsync {
​
    public static void main(String[] args) {
        SpringApplication.run(HelloWorldAsync.class, args);
    }
​
    // --- 生产者 ---
    @Bean
    public Queue helloQueue() {
        return new Queue("hello.queue");
    }
​
    @Bean
    public ApplicationRunner producer(RabbitTemplate template) {
        return args -> {
            for (int i = 0; i < 10; i++) {
                template.convertAndSend("hello.queue", "Message #" + i);
            }
            System.out.println("10 messages sent.");
        };
    }
​
    // --- 消费者 ---
    @RabbitListener(queues = "hello.queue")
    public void consumer(String message) {
        System.out.println("Received: " + message);
    }
}

14.3 订单处理系统(完整示例)

项目结构:

com.example.order
├── config
│   └── RabbitConfig.java
├── model
│   ├── Order.java
│   └── OrderResult.java
├── service
│   ├── OrderService.java
│   └── NotificationService.java
├── listener
│   └── OrderListener.java
├── controller
│   └── OrderController.java
└── OrderApplication.java

配置类:

@Configuration
public class RabbitConfig {
​
    // ============ Connection ============
    @Bean
    public CachingConnectionFactory connectionFactory() {
        CachingConnectionFactory factory = new CachingConnectionFactory("localhost");
        factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
        factory.setPublisherReturns(true);
        return factory;
    }
​
    // ============ Exchanges ============
    @Bean
    public TopicExchange orderExchange() {
        return ExchangeBuilder.topicExchange("order.exchange").durable(true).build();
    }
​
    @Bean
    public DirectExchange dlxExchange() {
        return new DirectExchange("order.dlx.exchange");
    }
​
    // ============ Queues ============
    @Bean
    public Queue orderCreateQueue() {
        return QueueBuilder.durable("order.create.queue")
                .withArgument("x-dead-letter-exchange", "order.dlx.exchange")
                .withArgument("x-dead-letter-routing-key", "order.dead")
                .build();
    }
​
    @Bean
    public Queue orderDeadQueue() {
        return QueueBuilder.durable("order.dead.queue").build();
    }
​
    @Bean
    public Queue notificationQueue() {
        return QueueBuilder.durable("order.notification.queue")
                .withArgument("x-dead-letter-exchange", "order.dlx.exchange")
                .withArgument("x-dead-letter-routing-key", "order.dead")
                .build();
    }
​
    // ============ Bindings ============
    @Bean
    public Binding createBinding() {
        return BindingBuilder.bind(orderCreateQueue())
                .to(orderExchange()).with("order.created");
    }
​
    @Bean
    public Binding deadBinding() {
        return BindingBuilder.bind(orderDeadQueue())
                .to(dlxExchange()).with("order.dead");
    }
​
    @Bean
    public Binding notificationBinding() {
        return BindingBuilder.bind(notificationQueue())
                .to(orderExchange()).with("order.*");
    }
​
    // ============ RabbitTemplate ============
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(jackson2MessageConverter());
​
        template.setConfirmCallback((correlationData, ack, cause) -> {
            String id = correlationData != null ? correlationData.getId() : "unknown";
            if (ack) {
                log.info("订单消息确认: {}", id);
            } else {
                log.error("订单消息发送失败: {}, 原因: {}", id, cause);
            }
        });
​
        template.setReturnsCallback(returned ->
                log.error("订单消息退回到 {}:{} — {}",
                        returned.getExchange(), returned.getRoutingKey(),
                        new String(returned.getMessage().getBody()))
        );
​
        return template;
    }
​
    // ============ Listener Container ============
    @Bean
    public SimpleRabbitListenerContainerFactory orderListenerFactory(
            ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setConcurrentConsumers(5);
        factory.setMaxConcurrentConsumers(20);
        factory.setPrefetchCount(50);
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setMessageConverter(jackson2MessageConverter());
​
        // 重试策略
        RetryTemplate retryTemplate = RetryTemplate.builder()
                .maxAttempts(3)
                .exponentialBackoff(1000, 2.0, 5000)
                .build();
​
        // 重试耗尽后发送到死信队列
        MessageRecoverer recoverer = new RepublishMessageRecoverer(
                rabbitTemplate(connectionFactory), "order.dlx.exchange", "order.dead");
        factory.setRetryTemplate(retryTemplate);
        factory.setRecoveryCallback(new RetryContextExhaustedMessageRecoverer(recoverer));
​
        return factory;
    }
​
    @Bean
    public Jackson2JsonMessageConverter jackson2MessageConverter() {
        Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
        // 信任所有包(生产环境应限制)
        converter.setClassMapper(new DefaultJackson2JavaTypeMapper());
        return converter;
    }
​
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }
}

监听器:

@Component
@Slf4j
public class OrderListener {
​
    @Autowired
    private OrderService orderService;
    @Autowired
    private NotificationService notificationService;
​
    @RabbitListener(queues = "order.create.queue",
            containerFactory = "orderListenerFactory")
    public void handleOrderCreated(
            Order order,
            Channel channel,
            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
            @Header(AmqpHeaders.RECEIVED_ROUTING_KEY) String routingKey)
            throws IOException {
​
        log.info("收到订单创建消息: routingKey={}, order={}", routingKey, order.getId());
​
        try {
            // 业务处理
            OrderResult result = orderService.processOrder(order);
​
            // 手动确认
            channel.basicAck(deliveryTag, false);
​
            log.info("订单处理完成: {}", result);
        } catch (OrderValidationException e) {
            // 校验失败,不重试,发送到死信
            log.warn("订单校验失败,移至死信: {}", order.getId());
            channel.basicReject(deliveryTag, false); // requeue=false
        } catch (Exception e) {
            // 其他异常,重新入队等待重试
            log.error("订单处理异常,重新入队: {}", order.getId(), e);
            channel.basicNack(deliveryTag, false, true);
        }
    }
​
    @RabbitListener(queues = "order.notification.queue")
    public void handleNotification(Order order) {
        // 所有订单事件都会触发通知(routing key = "order.*")
        notificationService.sendNotification(order);
    }
​
    @RabbitListener(queues = "order.dead.queue")
    public void handleDeadOrder(Order order) {
        // 死信处理:记录到数据库、告警、人工介入
        log.warn("死信订单,需人工处理: {}", order);
        orderService.saveDeadOrder(order);
    }
}

发送端(Controller):

@RestController
@RequestMapping("/orders")
public class OrderController {
​
    @Autowired
    private RabbitTemplate rabbitTemplate;
​
    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody Order order) {
        CorrelationData correlationData = new CorrelationData(order.getId());
        rabbitTemplate.convertAndSend(
                "order.exchange",
                "order.created",
                order,
                correlationData
        );
        return ResponseEntity.accepted().body("Order submitted: " + order.getId());
    }
​
    // 延迟订单(需安装 delayed message exchange 插件)
    @PostMapping("/delayed")
    public ResponseEntity<String> createDelayedOrder(@RequestBody Order order) {
        rabbitTemplate.convertAndSend(
                "order.exchange",
                "order.delayed",
                order,
                msg -> {
                    msg.getMessageProperties().setDelay(30000); // 30s 延迟
                    return msg;
                }
        );
        return ResponseEntity.accepted().body("Delayed order submitted");
    }
}

14.4 股票交易示例

@Component
@Slf4j
public class StockTrading {
​
    // === 市场数据发布者 ===
    @Scheduled(fixedRate = 1000)
    public void publishMarketData() {
        MarketData data = MarketData.random();
        rabbitTemplate.convertAndSend(
                "stock.exchange",
                "market." + data.getSymbol(),
                data
        );
    }
​
    // === 交易指令监听器 ===
    @RabbitListener(queues = "stock.trade.queue")
    public void handleTrade(TradeOrder order) {
        log.info("执行交易: symbol={}, qty={}, price={}",
                order.getSymbol(), order.getQuantity(), order.getPrice());
        // 交易逻辑
    }
​
    // === 行情监听器(Topic Exchange 通配符) ===
    @RabbitListener(queues = "stock.market.queue")
    public void handleMarketData(
            @Payload MarketData data,
            @Header(AmqpHeaders.RECEIVED_ROUTING_KEY) String routingKey) {
        log.info("[{}] {}: ¥{}/{}",
                routingKey, data.getSymbol(), data.getPrice(), data.getVolume());
    }
}

15. 组件开发示例

15.1 自定义消息后处理器

@Component
public class TraceIdMessagePostProcessor implements MessagePostProcessor {
​
    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setHeader("X-Trace-Id", MDC.get("traceId"));
        message.getMessageProperties().setHeader("X-Timestamp", Instant.now().toString());
        return message;
    }
​
    @Override
    public Message postProcessMessage(Message message, Correlation correlation) {
        return postProcessMessage(message);
    }
}
​
// 使用
template.convertAndSend("exchange", "key", payload, new TraceIdMessagePostProcessor());

15.2 自定义消息转换器

public class ProtobufMessageConverter implements MessageConverter {
​
    @Override
    public Message toMessage(Object object, MessageProperties messageProperties)
            throws MessageConversionException {
        if (object instanceof MessageLite) {
            byte[] bytes = ((MessageLite) object).toByteArray();
            messageProperties.setContentType("application/x-protobuf");
            return new Message(bytes, messageProperties);
        }
        throw new MessageConversionException("Unsupported type: " + object.getClass());
    }
​
    @Override
    public Object fromMessage(Message message) throws MessageConversionException {
        // 需要知道目标类型,可通过 header 传递
        String className = message.getMessageProperties().getHeader("__TypeId__");
        // ...
        return null;
    }
}

15.3 自定义 ConnectionFactory 包装器

public class MetricsConnectionFactory extends AbstractConnectionFactory {
​
    private final MeterRegistry meterRegistry;
    private final CachingConnectionFactory delegate;
​
    public MetricsConnectionFactory(CachingConnectionFactory delegate,
                                     MeterRegistry meterRegistry) {
        this.delegate = delegate;
        this.meterRegistry = meterRegistry;
    }
​
    @Override
    public Connection createConnection() throws AmqpException {
        Timer.Sample sample = Timer.start(meterRegistry);
        try {
            Connection conn = delegate.createConnection();
            sample.stop(meterRegistry.timer("rabbitmq.connection.create"));
            return conn;
        } catch (AmqpException e) {
            meterRegistry.counter("rabbitmq.connection.error").increment();
            throw e;
        }
    }
}

15.4 RabbitMQ Stream 插件使用

// 依赖:spring-rabbit-stream
@Configuration
public class StreamConfig {
​
    @Bean
    public Environment environment() {
        return Environment.builder()
                .host("localhost")
                .port(5552) // Stream 插件端口
                .username("guest")
                .password("guest")
                .build();
    }
​
    @Bean
    public RabbitStreamTemplate streamTemplate(Environment env) {
        RabbitStreamTemplate template = new RabbitStreamTemplate(env, "my-stream");
        // 发送
        template.convertAndSend(message);
        return template;
    }
​
    @RabbitListener(queues = "my-stream")  // Stream 队列
    public void handleStreamMessage(String message) {
        // 处理流消息
    }
}

15.5 日志 Appender(AMQP Logback Appender)

<!-- logback-spring.xml -->
<appender name="AMQP" class="org.springframework.amqp.rabbit.logback.AmqpAppender">
    <host>localhost</host>
    <port>5672</port>
    <username>guest</username>
    <password>guest</password>
    <virtualHost>/</virtualHost>
    <exchangeName>logs.exchange</exchangeName>
    <routingKeyPattern>app.%level</routingKeyPattern>
    <declareExchange>true</declareExchange>
    <applicationId>my-service</applicationId>
    <charset>UTF-8</charset>
    <durable>true</durable>
</appender>

16. 最佳实践清单

连接管理

  • 使用 CachingConnectionFactory 管理连接/Channel 缓存,避免频繁创建

  • 启用发布者确认publisher-confirm-type: correlated)和发布者返回publisher-returns: true

  • 配置 Channel 缓存大小,生产环境建议 50-100

  • 启用心跳requested-heartbeat: 60s),防止空闲连接被中间网络设备断开

  • 集群部署使用 addresses 属性,避免单点

  • 启用自动恢复,Broker 重启后自动重连

消息发送

  • 使用 convertAndSend(),让消息转换器处理序列化

  • 设置 CorrelationData,将业务 ID(如订单号)关联到确认回调

  • 实现 ConfirmCallback 和 ReturnsCallback,监控消息是否成功到达 Broker

  • 批量发送使用 BatchingRabbitTemplate 减少网络开销

  • 传递头信息使用 MessagePostProcessor,如 trace-id、timestamp

消息接收

  • 使用 @RabbitListener 替代编程式监听,代码更简洁

  • 选择合适的容器:Simple(事务/多队列)vs Direct(高吞吐/低延迟)

  • 合理设置并发concurrency(初始 3-5)、max-concurrency(峰值 10-20)

  • 合理设置 prefetch:高吞吐场景 100-500,低延迟场景 1-10

  • 批处理场景启用 batchListener=trueconsumerBatchEnabled=true

  • 手动确认模式(MANUAL) 在处理成功后显式 ACK

消息序列化

  • 使用 Jackson2JsonMessageConverter 作为默认转换器

  • 生产环境限制信任包setTrustedPackages),防止反序列化漏洞

  • 通过消息头传递类型信息__TypeId__),确保类型安全反序列化

  • ContentTypeDelegatingMessageConverter 支持多格式消息路由

异常处理与重试

  • 区分可重试异常与致命异常:临时异常重试,业务校验失败直接拒绝

  • 使用指数退避(exponential backoff) 代替固定间隔重试

  • 配置死信队列(DLX):重试耗尽后的消息进入死信,便于排查和补偿

  • 使用 RepublishMessageRecoverer 自动将失败消息重新发布

  • 重试次数建议 3-5 次,总退避时间不超过消息 TTL

事务

  • 需要原子性操作时才使用事务(如多个队列的发送必须在同一事务中)

  • 事务性能开销大,优先使用发布者确认 + 手动 ACK 保障可靠性

  • SimpleMessageListenerContainer 支持事务,Direct 不支持

Broker 配置

  • 使用 Builder APIExchangeBuilderQueueBuilder)声明资源

  • 队列设置为持久化durable=true),消息持久化发送

  • Quorum Queue 替代 Classic Mirrored Queue(RabbitMQ 3.8+)

  • 设置队列 TTL 和最大长度,防止消息堆积

  • 使用 RabbitAdmin 的自动声明,Broker 恢复后自动重建拓扑

监控与运维

  • 引入 Micrometer,监控消息发送/消费速率、延迟、错误率

  • BrokerEventListener 监听 Broker 可用性变化

  • 死信队列监控告警:DLQ 中有消息即告警

  • 连接池监控:Channel 获取超时、连接创建失败计数

测试

  • 单元测试使用 TestRabbitTemplateRabbitListenerTestHarness

  • 集成测试使用 @SpringRabbitTest + @RabbitAvailable(JUnit5)

  • Mock RabbitTemplate 在 Service 层测试中隔离 AMQP 依赖

安全

  • 启用 SSL/TLS 加密传输

  • 限制 Jackson 反序列化信任包

  • 使用单独的用户凭据,按最小权限原则分配 vhost 权限

  • 生产环境关闭管理端口公网访问(15672)


附录:Maven 完整依赖

<dependencies>
    <!-- Spring AMQP 核心 -->
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit</artifactId>
        <version>3.0.4</version>
    </dependency>
​
    <!-- RabbitMQ Stream 插件支持 -->
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit-stream</artifactId>
        <version>3.0.4</version>
    </dependency>
​
    <!-- Jackson JSON 支持 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
​
    <!-- Spring Retry(重试支持) -->
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>
​
    <!-- Micrometer(可观测性) -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-core</artifactId>
    </dependency>
​
    <!-- Spring Boot Starter(推荐) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
​
    <!-- 测试 -->
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值