Spring-RabbitMq配置一个消费端接入多个vhost

前言

最近遇到一个需求需要在项目中同时接收两个系统的消息,问题来了:
在A系统中消费B系统和C系统发过来的消息,但是

  1. B和C不在同一个vhost上,
  2. 甚至连访问的账号密码都不一样

该如何实现呢?答案是自定义ConnectionFactory和RabbitListenerContainerFactory

ContainerFactory

当我们使用@RabbitListener注解注册监听器时,不知道你有没有发现一个额外的参数containerFactory

@RabbitListener(queues = "queue.orderStatus", containerFactory = "OrderContainerFacory")

这个containerFactory 填的是bean名称,指向一个containerFactory 对象,containerFactory 的作用是什么?
配置消费行为的逻辑,例如如下

  • 指定连接工厂
  • 指定消息内容序列化的方式
  • 一次从mq中取出消息的数量
  • 消息的确认模式
  • 消费者线程的并发数
  • 消息重试次数

正常我们不指定containerFacory时,SpringBoot会为我们自动创建一个SimpleRabbitListenerContainerFactory,当我们要自定义ContainerFactory时,只需要将我们自定义的ContainerFactory注入到容器,此时Spring检查到项目中已有就不会自动创建,而是用我们的。
本文只是教大家如何使用,具体的原理就不在此处介绍,有兴趣可以参考org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

自定义CachingConnectionFactory

CachingConnectionFactory的作用是管理消费端与mq建立的连接,我们上面说的containerFacory也是基于此的基础来实现的。我
们要连接不同账号的VHost,那么就需要设置不同的CachingConnectionFactory。

如下,往容器中分别注入B系统和C系统的CachingConnectionFactory,
我们分别针对A系统和B系统单独设置了VHost,address,账号,密码参数

/**
 * rabbitMQ配置
 *
 * @author wangmeng
 * @since 2023/7/26
 */
@Configuration
@Slf4j
public class RabbitConfig {


    @Autowired
    RabbitProperties properties;


    /**
     * 指定连接为A系统
     *
     * @return mq连接
     */
    @Bean("gigaCachingConnectionFactory")
    @Primary
    public CachingConnectionFactory gigaCachingConnectionFactory(@Value("${spring.rabbitmq.giga.virtual-host}") String vHost,
                                                                 @Value("${spring.rabbitmq.giga.username}") String username,
                                                                 @Value("${spring.rabbitmq.giga.password}") String password) {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(properties.getAddresses());
        connectionFactory.setPort(properties.getPort());
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(vHost);
        return connectionFactory;
    }

    /**
     * 指定连接为B系统
     *
     * @return mq连接
     */
    @Bean
    public CachingConnectionFactory xyCachingConnectionFactory(@Value("${spring.rabbitmq.xy.virtual-host}") String vHost,
                                                               @Value("${spring.rabbitmq.xy.username}") String username,
                                                               @Value("${spring.rabbitmq.xy.password}") String password) {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(properties.getAddresses());
        connectionFactory.setPort(properties.getPort());
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(vHost);
        return connectionFactory;
    }
  }

自定义SimpleRabbitListenerContainerFactory

有了连接工厂后,就可以基于连接工厂来创建ContainerFactory,这里我们选择默认的实现SimpleRabbitListenerContainerFactory。


    /**
     * 配置A系统使用的containerFactory
     *
     * @param cachingConnectionFactory 连接配置
     * @return A的containerFactory
     */
    @Bean(name = "xyRabbitMqListenerContainerFactory")
    public SimpleRabbitListenerContainerFactory xyRabbitMqFactory(@Qualifier("xyCachingConnectionFactory") CachingConnectionFactory cachingConnectionFactory) {
        SimpleRabbitListenerContainerFactory listenerContainerFactory = new SimpleRabbitListenerContainerFactory();
        listenerContainerFactory.setConnectionFactory(cachingConnectionFactory);
        listenerContainerFactory.setMessageConverter(new SimpleMessageConverter());
        // 手动确认
        listenerContainerFactory.setAcknowledgeMode(properties.getListener().getSimple().getAcknowledgeMode());
        listenerContainerFactory.setPrefetchCount(properties.getListener().getSimple().getPrefetch());
        // 限制并发数为1
        listenerContainerFactory.setConcurrentConsumers(1);
        return listenerContainerFactory;
    }


    /**
     * 配置B系统使用的containerFactory
     *
     * @param cachingConnectionFactory 连接配置
     * @return A的containerFactory
     */
    @Bean(name = "gigaRabbitMqListenerContainerFactory")
    public SimpleRabbitListenerContainerFactory gigaRabbitMqFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
                                                                    @Qualifier("gigaCachingConnectionFactory") CachingConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory listenerContainerFactory = new SimpleRabbitListenerContainerFactory();
        listenerContainerFactory.setConnectionFactory(connectionFactory);
        listenerContainerFactory.setMessageConverter(new SimpleMessageConverter());
        // 手动确认
        listenerContainerFactory.setAcknowledgeMode(properties.getListener().getSimple().getAcknowledgeMode());
        listenerContainerFactory.setPrefetchCount(properties.getListener().getSimple().getPrefetch());
        // 限制并发数为1
        listenerContainerFactory.setConcurrentConsumers(1);
        return listenerContainerFactory;
    }

为队列绑定ContainerFactory

有了如上的配置,就可以为队列指定对应的containerFacory了

我们分别在两个消费者的注解里指定对应的containerFacory

@RabbitListener(queues = "queue.order", containerFactory = "xyRabbitMqListenerContainerFactory")
public class CustomsClearConsumer extends BaseConsumer {
// 省略业务代码……

}


@RabbitListener(queues = "queue.ship", containerFactory = "gigaRabbitMqListenerContainerFactory")
public class ShipConsumer  extends BaseConsumer {
// 省略业务代码……

}


  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 中使用 RabbitMQ 时,我们可以通过在配置文件中配置绑定关系,将交换机和队列进行绑定。具体步骤如下: 1. 在 application.properties 或 application.yml 中配置 RabbitMQ 连接信息: ``` spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest ``` 2. 创建一个交换机和一个队列,并将它们绑定在一起: ``` @Configuration public class RabbitConfig { @Bean public Queue queue() { return new Queue("myqueue", true); } @Bean public DirectExchange exchange() { return new DirectExchange("myexchange"); } @Bean public Binding binding(Queue queue, DirectExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with("mykey"); } } ``` 3. 在需要发送消息的地方,注入 RabbitTemplate 并调用 convertAndSend 方法: ``` @Autowired private RabbitTemplate rabbitTemplate; public void sendMessage(String message) { rabbitTemplate.convertAndSend("myexchange", "mykey", message); } ``` 4. 在需要接收消息的地方,注入 SimpleMessageListenerContainer 并实现 MessageListener 接口: ``` @Autowired private Queue queue; @Bean public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames(queue.getName()); container.setMessageListener(listenerAdapter); return container; } @Bean public MessageListenerAdapter listenerAdapter() { return new MessageListenerAdapter(new MyMessageListener()); } public class MyMessageListener implements MessageListener { @Override public void onMessage(Message message) { String body = new String(message.getBody()); System.out.println("Received message: " + body); } } ``` 通过以上步骤,我们就可以实现交换机和队列的绑定,以及在队列中发送和接收消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值