SpringBoot集成flowable6.5的事件注册引擎后rabbitmq消费者不自动开启问题

背景

flowable6.5后新增了事件注册引擎,对JMS,Apache Kafka和RabbitMQ具有开箱即用的支持。如果想支持其他的消息中间件也可通过添加自己的适配器来实现。

问题

SpringBoot项目中集成flowable6.5的事件注册引擎后,项目之前rabbitmq消费者不会自动开启。

项目之前配置有RabbitMQ的的消费者(其中autoStartup可以指定是否自动开启)

@Service
public class MQListener {
	@RabbitListener(queues = "xxxx",autoStartup = "true")
	public void handle(Channel channel, Message message) throws IOException {
	    ...
	}
}

部署channel、event到flowable的事件注册引擎。启动项目后发现MQListener配置的那些消费者不会启动。

问题跟踪

先阐述以下几个类的关系、作用

RabbitListener:加在方法上的注解,记录着一个消费者的相关信息(监听队列、是否自动开启、ack模式等)
RabbitListenerEndpoint:消费者终端,真正操作rabbitmq
MessageListenerContainer:管理RabbitListenerEndpoint的容器
RabbitListenerEndpointRegistry: 管理RabbitListenerEndpoint的注册器
他们之间的关系:RabbitListener ---根据配置创建→ RabbitListenerEndpoint ---注入→ MessageListenerContainer ---注入→ RabbitListenerEndpointRegistry

要开启消费需要调RabbitListenerEndpoint的start()方法,调MessageListenerContainer的start()会间接调RabbitListenerEndpoint的start()方法,而调RabbitListenerEndpointRegistry也会间接调MessageListenerContainer的start()方法

所以想要RabbitListenerEndpoint自动开启,一种方式是调RabbitListenerEndpointRegistry的start()方法。

在spring的AbstractApplicationContext类中,当走到finishRefresh()阶段时,就会从容器中取出所有实现了Lifecycle接口的bean,根据判断是否要调用start()方法。
在这里插入图片描述
在这里插入图片描述
而RabbitListenerEndpointRegistry是实现Lifecycle的接口的(通过SmartLifecycle间接实现),跟进去看到,只要有一个MessageListenerContainer是正在运行的话就会返回true, 这时!bean.isRunning()就是false了!
在这里插入图片描述
而一开始注册到RabbitListenerEndpointRegistry的MessageListenerContainer是不会开启的(具体可以看RabbitListenerEndpointRegistrar类的源码),但flowable的自动注入的RabbitChannelDefinitionProcessor类中,向RabbitListenerEndpointRegistry
注入的MessageListenerContainer是马上开启的,如下代码在这里插入图片描述
在这里插入图片描述

解决方案

根据上面跟踪源码找到原因后,最后解决方案是注入一个名为rabbitChannelDefinitionProcessor的bean,继承RabbitChannelDefinitionProcessor,重写其中的一些方法,如下:

@Service("rabbitChannelDefinitionProcessor")
public class RabbitMQProcessor extends RabbitChannelDefinitionProcessor implements InitializingBean {

    @Autowired
    private RabbitListenerEndpointRegistry endpointRegistry;
    @Autowired
    private RabbitOperations rabbitOperations;
    
	@Override
    protected RabbitListenerEndpoint createRabbitListenerEndpoint(RabbitInboundChannelModel channelModel, String tenantId, EventRegistry eventRegistry) {
        final SimpleRabbitListenerEndpoint endpoint = (SimpleRabbitListenerEndpoint) super.createRabbitListenerEndpoint(channelModel, tenantId, eventRegistry);
        endpoint.setAutoStartup(true);
        return endpoint;
    }

    @Override
    protected void registerEndpoint(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory) {
        Assert.notNull(endpoint, "Endpoint must not be null");
        Assert.hasText(endpoint.getId(), "Endpoint id must be set");

        Assert.state(this.endpointRegistry != null, "No RabbitListenerEndpointRegistry set");
        endpointRegistry.registerListenerContainer(endpoint, resolveContainerFactory(endpoint, factory));
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        super.setEndpointRegistry(endpointRegistry);
        super.setRabbitOperations(rabbitOperations);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章