spring rabbitmq在配置多数据源时,先加载的链接会创建不同vhost所有交换机以及队列

在项目中使用到了rabbitmq,项目是基于springboot的,所以理所应当的使用了spring包装的rabbitmq工具。需要时要配置不同的数据源,分成相应的消费者从不同交换机下的不同队列进行消费。

当然由于平时使用rabbitmq都是单数据源,从网上借鉴了一些配置多数据源的demo,例如:

@Configuration
public class RabbitConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitConfiguration.class);

    @Resource(name = "accountUnbindHost")
    private Host accountUnbindHost;

    @Resource(name = "cardUnbindHost")
    private Host cardUnbindHost;

    @Bean(name = "accountUnbindConnectionFactory")
    @Primary
    public ConnectionFactory accountUnbindConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(accountUnbindHost.getAddresses());
        connectionFactory.setUsername(accountUnbindHost.getUsername());
        connectionFactory.setPassword(accountUnbindHost.getPassword());
        connectionFactory.setVirtualHost(accountUnbindHost.getVirtualHost());
        return connectionFactory;
    }

    @Bean(name = "accountUnbindListenerContainer")
    @Primary
    public SimpleRabbitListenerContainerFactory accountUnbindListenerContainer(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            @Qualifier("accountUnbindConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }
//
//    @Bean(name = "accountUnbindRabbitTemplate")
//    @Primary
//    public RabbitTemplate accountUnbindrabbitTemplate(@Qualifier("accountUnbindConnectionFactory") ConnectionFactory connectionFactory) {
//        return new RabbitTemplate(connectionFactory);
//    }
    /**
     * 声明账户解绑交换机
     */
    @Bean
    FanoutExchange accountUnBindFanoutExchange() {
        //  return new FanoutExchange
        return new FanoutExchange(CommonConstant.ACCOUNT_UBIND_FANOUT_EXCHANGE_NAME,true,false);
    }

    /**
     * 声明账户解绑队列,扇形交换机会广播到每个绑定的队列
     */
    @Bean
    public Queue accountUnBindQueue() {
        return new Queue(CommonConstant.ACCOUNT_UBIND_QUEUE_NAME, true);
    }

    //绑定 将队列和交换机绑定
    @Bean
    Binding bindingAccountUnBind() {
        return BindingBuilder.bind(accountUnBindQueue()).to(accountUnBindFanoutExchange());
    }

    @Bean(name = "cardUnbindConnectionFactory")
    public ConnectionFactory cardUnbindConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(cardUnbindHost.getAddresses());
        connectionFactory.setUsername(cardUnbindHost.getUsername());
        connectionFactory.setPassword(cardUnbindHost.getPassword());
        connectionFactory.setVirtualHost(cardUnbindHost.getVirtualHost());
        return connectionFactory;
    }

    @Bean(name = "cardUnbindListenerContainer")
    public SimpleRabbitListenerContainerFactory cardUnbindistenerContainer(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            @Qualifier("cardUnbindConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    @Bean(name = "cardUnbindRabbitTemplate")
    public RabbitTemplate cardUnbindRabbitTemplate(@Qualifier("cardUnbindConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitTemplate(connectionFactory);
    }

    /**
     * 声明银行卡解绑交换机
     */
    @Bean
    FanoutExchange cardUnbindFanoutExchange() {
        //  return new FanoutExchange
        return new FanoutExchange(CommonConstant.CARD_UBIND_FANOUT_EXCHANGE_NAME,true,false);
    }

    /**
     * 声明银行卡解绑队列,扇形交换机会广播到每个绑定的队列
     */
    @Bean
    public Queue cardUnbindQueue() {
        return new Queue(CommonConstant.CARD_UBIND_QUEUE__NAME, true);
    }

    //绑定 将队列和交换机绑定
    @Bean
    Binding bindingCardUnbind() {
        return BindingBuilder.bind(cardUnbindQueue()).to(cardUnbindFanoutExchange());
    }
}

然而在使用的过程中并不顺利,不同的两个ip以及vhost,在第一个vhost竟然创建了第二个vhost需要的交换机以及队列。

在spring初始化的过程中,@Primary标注的类,会作为优先加载项,如下图所示,从RabbitAutoConfiguration进行初始化:

RabbitAdmin类实现了InitializingBean接口,因此在初始化完bean之后,会执行实现该接口中的afterPropertiesSet方法:

从该方法可以看出链接工厂实例connectionFactory会添加链接监听器,用于在链接建立完成之后,执行该监听方法:

该监听函数式接口实现:

connection -> {

                if (!initializing.compareAndSet(false, true)) {
                    // If we are already initializing, we don't need to do it again...
                    return;
                }
                try {
                    /*
                     * ...but it is possible for this to happen twice in the same ConnectionFactory (if more than
                     * one concurrent Connection is allowed). It's idempotent, so no big deal (a bit of network
                     * chatter). In fact it might even be a good thing: exclusive queues only make sense if they are
                     * declared for every connection. If anyone has a problem with it: use auto-startup="false".
                     */
                    if (this.retryTemplate != null) {
                        this.retryTemplate.execute(c -> {
                            initialize();
                            return null;
                        });
                    }
                    else {
                        initialize();
                    }
                }
                finally {
                    initializing.compareAndSet(true, false);
                }

            }

对于交换机以及队列的创建就是在该函数式方法中的initialize(),如下图所示:

在该方法中,会查询出spring管理的所有交换机、队列以及绑定,紧接着就是在信道中创建交换机、队列以及绑定,如下图:

只要是在文章初始中的RabbitConfiguration声明的交换机以及bean都会在该信道中创建,因此就导致了开头中的问题:

由于/cif的链接是是优先配置项,因此本不属于自己的bcm_x交换机也被创建。

那么何时会调用RabbitAutoConfiguration自动加载时的RabbitAdmin呢,上文提到了是在初始化完bean之后。怎么解决该问题呢?就是自己定义RabbitAdmin:

    @Bean(name = "cardUnbindRabbitAdmin")
    public RabbitAdmin cardUnbindRabbitAdmin(@Qualifier("cardUnbindConnectionFactory") ConnectionFactory connectionFactory) {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean(name = "cardUnbindRabbitTemplate")
    public RabbitTemplate cardUnbindRabbitTemplate(@Qualifier("cardUnbindConnectionFactory") ConnectionFactory connectionFactory) {
        return new RabbitTemplate(connectionFactory);
    }

    /**
     * 声明银行卡解绑交换机
     */
    @Bean
    FanoutExchange cardUnbindFanoutExchange(@Qualifier("cardUnbindRabbitAdmin") RabbitAdmin rabbitAdmin) {
        FanoutExchange fanoutExchange = new FanoutExchange(CommonConstant.CARD_UBIND_FANOUT_EXCHANGE_NAME,true,false);
        fanoutExchange.setAdminsThatShouldDeclare(rabbitAdmin);
        //  return new FanoutExchange
        return fanoutExchange;
    }
    /**
     * 声明银行卡解绑队列,扇形交换机会广播到每个绑定的队列
     */
    @Bean
    public Queue cardUnbindQueue(@Qualifier("cardUnbindRabbitAdmin") RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(CommonConstant.CARD_UBIND_QUEUE__NAME, true);
        queue.setAdminsThatShouldDeclare(rabbitAdmin);
        return queue;
    }

    //绑定 将队列和交换机绑定
    @Bean
    Binding bindingCardUnbind(@Qualifier("cardUnbindRabbitAdmin") RabbitAdmin rabbitAdmin) {
        Binding binding = BindingBuilder.bind(cardUnbindQueue(rabbitAdmin)).to(cardUnbindFanoutExchange(rabbitAdmin));
        binding.setAdminsThatShouldDeclare(rabbitAdmin);
        return binding;
    }

通过自定义的RabbitAdmin,setAdminsThatShouldDeclare表明交换机、队列以及绑定与该RabbitAdmin绑定,在initialize()方法中,下段代码会将不属于自己的交换机、队列以及绑定过滤掉,从而达到只会声明自己的配置。

spring rabbitmq的其他源码属实有点抽象,害,还得努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值