Spring Boot 4.0 整合 RabbitMQ 注解方式使用指南

Spring Boot 4.0 整合 RabbitMQ 注解方式使用指南

我将基于最新的 Spring Boot 4.x 版本(包含 Spring Framework 6.0 的新特性)为您演示 RabbitMQ 的注解整合方式。这些内容同样适用于未来的 Spring Boot 4.0。

1. 环境准备

1.1 创建项目

xml 复制代码
<!-- pom.xml 主要依赖 -->
<dependencies>
    <!-- Spring Boot 4.x -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- 可选: 消息转换器 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

2. 基础配置

2.1 配置文件

yaml 复制代码
# application.yml
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    # 连接池配置 (Spring Boot 3.x 新特性)
    connection-timeout: 5s
    # 发布确认
    publisher-confirm-type: correlated
    publisher-returns: true
    template:
      mandatory: true
    listener:
      simple:
        acknowledge-mode: manual  # 手动确认
        retry:
          enabled: true
          max-attempts: 3
          initial-interval: 2s

3. 注解方式实现

3.1 声明队列、交换机和绑定

typescript 复制代码
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {
    
    // 1. 声明队列 (使用新版的Builder模式)
    @Bean
    public Queue orderQueue() {
        return QueueBuilder.durable("order.queue")
                .deadLetterExchange("dlx.exchange")
                .deadLetterRoutingKey("order.dl")
                .ttl(10000)  // 10秒过期
                .maxLength(1000)
                .build();
    }
    
    @Bean
    public Queue dlQueue() {
        return QueueBuilder.durable("dl.order.queue").build();
    }
    
    // 2. 声明交换机
    @Bean
    public DirectExchange orderExchange() {
        return ExchangeBuilder
                .directExchange("order.exchange")
                .durable(true)
                .build();
    }
    
    @Bean
    public DirectExchange dlxExchange() {
        return ExchangeBuilder
                .directExchange("dlx.exchange")
                .durable(true)
                .build();
    }
    
    // 3. 声明绑定
    @Bean
    public Binding orderBinding(Queue orderQueue, DirectExchange orderExchange) {
        return BindingBuilder
                .bind(orderQueue)
                .to(orderExchange)
                .with("order.routing.key");
    }
    
    @Bean
    public Binding dlBinding(Queue dlQueue, DirectExchange dlxExchange) {
        return BindingBuilder
                .bind(dlQueue)
                .to(dlxExchange)
                .with("order.dl");
    }
    
    // 4. 延迟队列插件 (RabbitMQ 延迟消息插件)
    @Bean
    public Queue delayedQueue() {
        return QueueBuilder.durable("delayed.queue")
                .withArgument("x-delayed-type", "direct")
                .build();
    }
    
    @Bean
    public CustomExchange delayedExchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(
            "delayed.exchange", 
            "x-delayed-message", 
            true, 
            false, 
            args
        );
    }
}

3.2 生产者服务

typescript 复制代码
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.UUID;

@Service
public class MessageProducer {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 发送简单消息
     */
    public void sendSimpleMessage(String message) {
        rabbitTemplate.convertAndSend(
            "order.exchange", 
            "order.routing.key", 
            message
        );
    }
    
    /**
     * 发送对象消息
     */
    public void sendOrderMessage(Order order) {
        rabbitTemplate.convertAndSend(
            "order.exchange", 
            "order.routing.key", 
            order,
            message -> {
                // 设置消息属性
                message.getMessageProperties()
                    .setContentType("application/json");
                return message;
            }
        );
    }
    
    /**
     * 发送确认消息
     */
    public void sendConfirmMessage(String message) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        
        rabbitTemplate.convertAndSend(
            "order.exchange", 
            "order.routing.key", 
            message,
            correlationData
        );
    }
    
    /**
     * 发送延迟消息
     */
    public void sendDelayedMessage(String message, int delayMillis) {
        Message msg = MessageBuilder
            .withBody(message.getBytes())
            .setHeader("x-delay", delayMillis)
            .build();
            
        rabbitTemplate.send(
            "delayed.exchange", 
            "delayed.routing.key", 
            msg
        );
    }
    
    /**
     * 发布者确认回调
     */
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                System.out.println("消息发送成功: " + correlationData);
            } else {
                System.out.println("消息发送失败: " + cause);
            }
        });
        
        rabbitTemplate.setReturnsCallback(returned -> {
            System.out.println("消息路由失败: " + returned.getMessage());
        });
    }
}

3.3 消费者服务

less 复制代码
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import java.io.IOException;

@Component
@RabbitListener(
    bindings = @QueueBinding(
        value = @Queue(
            value = "order.queue",
            arguments = {
                @Argument(name = "x-dead-letter-exchange", value = "dlx.exchange"),
                @Argument(name = "x-dead-letter-routing-key", value = "order.dl"),
                @Argument(name = "x-message-ttl", value = "10000", type = "java.lang.Long")
            }
        ),
        exchange = @Exchange(value = "order.exchange", type = ExchangeTypes.DIRECT),
        key = "order.routing.key"
    )
)
public class MessageConsumer {
    
    /**
     * 基础消息消费
     */
    @RabbitHandler
    public void process(@Payload String message) {
        System.out.println("收到消息: " + message);
    }
    
    /**
     * 对象消息消费
     */
    @RabbitHandler
    public void processOrder(@Payload Order order) {
        System.out.println("收到订单: " + order);
    }
    
    /**
     * 手动确认消息
     */
    @RabbitListener(queues = "manual.queue")
    public void processManual(Message message, Channel channel) throws IOException {
        try {
            System.out.println("处理消息: " + new String(message.getBody()));
            
            // 业务处理
            // ...
            
            // 手动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            
        } catch (Exception e) {
            // 消息重入队列
            channel.basicNack(
                message.getMessageProperties().getDeliveryTag(), 
                false, 
                true
            );
        }
    }
    
    /**
     * 死信队列监听
     */
    @RabbitListener(queues = "dl.order.queue")
    public void processDlMessage(String message) {
        System.out.println("死信队列收到消息: " + message);
    }
    
    /**
     * 延迟消息监听
     */
    @RabbitListener(queues = "delayed.queue")
    public void processDelayedMessage(String message) {
        System.out.println("收到延迟消息: " + message);
    }
}

4. 高级特性示例

4.1 批量消费者

typescript 复制代码
@Component
public class BatchConsumer {
    
    /**
     * 批量消费 (Spring Boot 3.x 新特性优化)
     */
    @RabbitListener(
        queues = "batch.queue",
        containerFactory = "batchContainerFactory"
    )
    public void processBatch(List<Message> messages) {
        for (Message message : messages) {
            System.out.println("批量处理消息: " + new String(message.getBody()));
        }
    }
}

4.2 批量容器工厂配置

dart 复制代码
@Configuration
public class BatchRabbitConfig {
    
    @Bean
    public SimpleRabbitListenerContainerFactory batchContainerFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            ConnectionFactory connectionFactory) {
        
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        
        // 开启批量消费
        factory.setBatchListener(true);
        factory.setConsumerBatchEnabled(true);
        factory.setBatchSize(10);  // 每批10条
        factory.setReceiveTimeout(3000L);  // 接收超时3秒
        
        return factory;
    }
}

4.3 消息转换器配置

java 复制代码
@Configuration
public class MessageConverterConfig {
    
    @Bean
    public MessageConverter messageConverter() {
        // 使用Jackson2JsonMessageConverter替代默认的SimpleMessageConverter
        Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
        converter.setUseProjectionForInterfaces(true);  // 支持接口投影
        converter.setUseJavaTypeForMapper(true);
        return converter;
    }
    
    @Bean
    public RabbitTemplate rabbitTemplate(
            ConnectionFactory connectionFactory,
            MessageConverter messageConverter) {
        
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(messageConverter);
        
        // 开启返回模式
        template.setMandatory(true);
        
        return template;
    }
}

5. 完整应用示例

5.1 控制层

less 复制代码
@RestController
@RequestMapping("/rabbitmq")
public class RabbitMQController {
    
    @Autowired
    private MessageProducer messageProducer;
    
    @PostMapping("/send")
    public String sendMessage(@RequestParam String message) {
        messageProducer.sendSimpleMessage(message);
        return "消息发送成功";
    }
    
    @PostMapping("/send-order")
    public String sendOrder(@RequestBody Order order) {
        messageProducer.sendOrderMessage(order);
        return "订单消息发送成功";
    }
    
    @PostMapping("/send-delayed")
    public String sendDelayed(
            @RequestParam String message,
            @RequestParam int delaySeconds) {
        messageProducer.sendDelayedMessage(message, delaySeconds * 1000);
        return "延迟消息发送成功";
    }
}

5.2 实体类

less 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
    private String orderId;
    private String orderNo;
    private BigDecimal amount;
    private LocalDateTime createTime;
}

6. 测试验证

6.1 测试类

typescript 复制代码
@SpringBootTest
class RabbitmqApplicationTests {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Test
    void testSendAndReceive() {
        // 发送消息
        rabbitTemplate.convertAndSend(
            "order.exchange", 
            "order.routing.key", 
            "Hello RabbitMQ"
        );
        
        // 接收消息
        Object message = rabbitTemplate.receiveAndConvert("order.queue", 3000);
        assertNotNull(message);
    }
    
    @Test
    void testObjectMessage() {
        Order order = new Order("123", "ORD2023001", new BigDecimal("100.00"), LocalDateTime.now());
        rabbitTemplate.convertAndSend("order.exchange", "order.routing.key", order);
    }
}

7. 最佳实践建议

7.1 消息确认策略

  • 生产环境建议开启 publisher-confirmspublisher-returns
  • 消费者根据业务需要选择自动确认或手动确认

7.2 错误处理

kotlin 复制代码
@Component
public class RabbitMQErrorHandler {
    
    /**
     * 全局异常处理
     */
    @Bean
    public RabbitListenerErrorHandler rabbitListenerErrorHandler() {
        return (amqpMessage, message, exception) -> {
            // 记录错误日志
            System.err.println("RabbitMQ 消息处理异常: " + exception.getMessage());
            
            // 可以根据异常类型进行不同处理
            if (exception instanceof BusinessException) {
                // 业务异常,记录但不重试
                return null;
            } else {
                // 系统异常,抛出以触发重试
                throw exception;
            }
        };
    }
}

7.3 监控和指标

yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,rabbit
  metrics:
    export:
      rabbit:
        enabled: true

总结

通过以上注解方式的实现,您可以:

  1. 快速上手:通过简单的注解即可实现消息的发送和接收
  2. 高级特性:支持延迟消息、死信队列、批量消费等高级功能
  3. 可靠性:支持发布确认、消费确认、重试机制
  4. 维护性:配置集中管理,代码结构清晰
  5. 可扩展:易于添加新队列和消费者
相关推荐
名字还没想好☜24 分钟前
Java 用 LinkedHashMap 三行实现 LRU 缓存:accessOrder、removeEldestEntry 与线程安全
java·后端·安全·spring·缓存
谢亮_vipxieliang37 分钟前
ValidX vs Google Guava Preconditions:验证 vs 断言
java·spring boot·后端·spring cloud·hibernate·guava
mldong8 小时前
C# 开发者也有自己的轻量工作流引擎了:NuGet 装包,5 分钟跑通一条审批流
后端·c#·.net
爱学堂IT分享10 小时前
鹤翔老师pmp项目管理培训认证考试课 (直播录播题库送学时证明)【共58课时】-51CTO学堂
后端
王的宝库10 小时前
Go 项目结构:从单文件到标准工程布局
开发语言·后端·golang
码事漫谈11 小时前
类型即世界:一个 C++ 程序员的本体论入门
后端
Rain的Java大神之路12 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
IT_陈寒14 小时前
Python的多线程居然是个假把式?搞清GIL让我少熬三天夜
前端·人工智能·后端
明月_清风14 小时前
位图与布隆过滤器:海量数据下的"存在性判断"艺术
前端·后端·算法
明月_清风14 小时前
Hash 表从入门到精通:Go 实战与工程细节
前端·后端·算法