RabbitMQ动态监听浅析

rabbitmq动态监听浅记

浅析背景

使用rabbitmq时遇到需要进行队列拆分,比如拆成10个,my.queue.0-my.queue.9;消费者上需要完成对不同队列的消费,比如消费者1消费0.1队列,消费者消费2.3队列。

rabbitmq基础使用方式

基于spring-rabbitmq常见的使用方式是基于@RabbitListener完成RabbitListenerEndPoint定义及MessageListenerContainer的定义。基于这种使用方式不能满足动态监听的需要。所以选择模拟@RabbitListener的工作流程的方式实现,通过编码式生成RabbitListenerEndPoint,并注册到RabbitListenerEndPointRegistry上。

public void registerListenerContainer(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory) {
        this.registerListenerContainer(endpoint, factory, false);
    }

手动注册可能存在的问题

这里描述的问题是由于项目已经通过@RabbitListener完成MessageListenerContainer的定义,通过RabbitListenerEndPointRegistry实现的LifeCycle接口在Spring容器启动的finishRefresh阶段完成LifeCycle初始化及start()的调用。而通过模拟@RabbitListener的工作流程中,通常会手动启动MessageListenerContainer,而@RabbitListener和模拟的MessageListenerContainer是注册到同一RabbitListenerEndPointRegistry上,由于手动启动MessageListenerContainer的原因而导致RabbitListenerEndPointRegistry提前处于isRunning的状态,引起后续LifeCycle执行阶段不执行LifeCycle的start()方法。这里可以查看DefaultLifeCycleProcessor的doStart()。

public boolean isRunning() {
        Iterator var1 = this.getListenerContainers().iterator();

        MessageListenerContainer listenerContainer;
        do {
            if (!var1.hasNext()) {
                return false;
            }

            listenerContainer = (MessageListenerContainer)var1.next();
        } while(!listenerContainer.isRunning());

        return true;
    }

只要任何一个MessageListenerContainer处于running中则RabbitListenerEndPointRegistry处于running状态

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
        Lifecycle bean = (Lifecycle)lifecycleBeans.remove(beanName);
        if (bean != null && bean != this) {
            String[] dependenciesForBean = this.getBeanFactory().getDependenciesForBean(beanName);
            String[] var6 = dependenciesForBean;
            int var7 = dependenciesForBean.length;

            for(int var8 = 0; var8 < var7; ++var8) {
                String dependency = var6[var8];
                this.doStart(lifecycleBeans, dependency, autoStartupOnly);
            }

            if (!bean.isRunning() && (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle)bean).isAutoStartup())) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]");
                }

                try {
                    bean.start();
                } catch (Throwable var10) {
                    throw new ApplicationContextException("Failed to start bean '" + beanName + "'", var10);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Successfully started bean '" + beanName + "'");
                }
            }
        }

    }

可能的解决方式

方式一: 手动注册的RabbitListenerEndPoint autoStartUp设置为true,不手动启动
方式二(未确认):手动注册的RabbitListenerEndPoint autoStartUp还是设置成默认值false,应用启动过程中可以正常先启动@RabbitListener对应的MessageListenerContainer;然后通过实现Spring相关的接口如SpringApplicationRunListener对应的方法如running,在running中手动启动手动注册的MessageListenerContainer。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值