RabbitMQ配置类的最佳实现

5 阅读2分钟

前言

此配置类会在需要配置多台 mq 时用到. 通过注解指定大多数配置,降低整个消息队列的耦合度

  1. 启动类配置
@SpringBootApplication(exclude = {RabbitAutoConfiguration.class})   //一定要显式屏蔽,不然监听器注解会使用默认的连接工厂
@EnableRabbit       //一定要显式开启
public class RabbitmqHardApplication {
    public static void main(String[] args) {
        SpringApplication.run(RabbitmqHardApplication.class, args);
    }

}
  1. 配置类代码(包含交换机队列创建、模板消息配置、连接容器工厂配置)
@Slf4j
@Configuration
public class RabbitmqConfig {

    @Value("${rabbitmq.host:localhost}")
    private String host;

    @Value("${rabbitmq.port:5672}")
    private int port;

    @Value("${rabbitmq.username:admin}")
    private String username;

    @Value("${rabbitmq.password:admin}")
    private String password;

    @Value("${rabbitmq.virtual-host:/}")
    private String virtualHost;



    // 队列名称常量
    public static final String SIMPLE_QUEUE = "simple.queue";

    // 交换机名称常量
    public static final String SIMPLE_EXCHANGE = "simple.exchange";

    // 路由键常量
    public static final String SIMPLE_ROUTING_KEY = "simple.routing.key";


    @Bean("connectionFactory")
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);

        // 连接池配置
        connectionFactory.setChannelCacheSize(25);

        //### 可靠性配置 ###

        // 启用发布确认机制
        connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);

        // 启用发布返回机制
        connectionFactory.setPublisherReturns(true);

        return connectionFactory;
    }

    @Bean("rabbitListenerContainerFactory")
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(@Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);

        // 设置并发消费者数量
        factory.setConcurrentConsumers(1);
        factory.setMaxConcurrentConsumers(5);

        // 设置预取计数,控制每个消费者一次处理的消息数量
        factory.setPrefetchCount(10);

        // 设置确认模式(根据业务需要选择)
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 手动 ack


        return factory;
    }


    /**
     * 声明一个简单队列
     * @return Queue对象
     */
    @Bean("simpleQueue")
    public Queue simpleQueue() {
        return QueueBuilder.durable(SIMPLE_QUEUE).build();
    }

    /**
     * 声明一个简单交换机
     * @return DirectExchange对象
     */
    @Bean("simpleExchange")
    public DirectExchange simpleExchange() {
        return new DirectExchange(SIMPLE_EXCHANGE);
    }

    /**
     * 绑定队列和交换机
     * @param simpleQueue 队列
     * @param simpleExchange 交换机
     * @return Binding对象
     */
    @Bean("simpleBinding")
    public Binding simpleBinding(Queue simpleQueue, DirectExchange simpleExchange) {
        return BindingBuilder.bind(simpleQueue)
                .to(simpleExchange)
                .with(SIMPLE_ROUTING_KEY);
    }

    @Bean("rabbitAdmin")
    public RabbitAdmin rabbitAdmin(@Qualifier("simpleQueue") Queue simpleQueue,@Qualifier("simpleExchange") DirectExchange simpleExchange,@Qualifier("simpleBinding") Binding simpleBinding,@Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.declareQueue(simpleQueue);
        rabbitAdmin.declareExchange(simpleExchange);
        rabbitAdmin.declareBinding(simpleBinding);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);

        // 设置消息确认回调 ---> 发布者确认
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                // 消息成功投递到Broker
                log.info("消息投递成功: {}", correlationData != null ? correlationData.getId() : "unknown");
            } else {
                // 消息投递失败
                log.error("消息投递失败: {},原因: {}",
                        correlationData != null ? correlationData.getId() : "unknown", cause);
            }
        });

        // 设置消息返回回调 ---> 处理无法路由到队列的情况
        rabbitTemplate.setReturnsCallback(returned -> {
            log.warn("消息返回: exchange={}, routingKey={}, message={}",
                    returned.getExchange(), returned.getRoutingKey(), returned.getMessage());
        });

        // 设置默认交换机和路由键
        rabbitTemplate.setExchange(SIMPLE_EXCHANGE);
        rabbitTemplate.setRoutingKey(SIMPLE_ROUTING_KEY);

        // 设置消息序列化方式
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        // 启用强制返回模式
        rabbitTemplate.setMandatory(true);

        return rabbitTemplate;
    }



}
  1. 消费者配置
@Slf4j
@Component
public class QueueConsumer{

    @RabbitListener(queues = SIMPLE_QUEUE, containerFactory = "rabbitListenerContainerFactory")
    public void handleMessage(Message message, Channel channel) throws IOException {
        try {
            log.info(">>>>>>>>>>>接收到了消息 : {}", message);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // 拒绝消息并决定是否重新排队
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            log.error(e.getMessage());
        }
    }
}