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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章