深入理解DefaultMessageListenerContainer

  DefaultMessageListenerContainer是一个用于异步消息监听的管理类。

  DefaultMessageListenerContainer最简单的实现逻辑,一个任务执行器,执行任务(即消息监听)。

  DefaultMessageListenerContainer实现的主要原理是,通过内部初始化建立的一个taskExecutor(默认是SimpleAsyncTaskExecutor)用于执行消息监听的任务(AsyncMessageListenerInvoker)。

 这里默认的任务执行器是SimpleAsyncTaskExecutor,这个执行器的缺点是不会重用连接,也就是对于每个任务都需要新开启一个线程,执行完任务后会关闭它。如果要优化的话可以考虑线程池。

 消息监听的任务被抽象成AsyncMessageListenerInvoker类,这个类实现了Runnable接口,内部run方法其实是通过不断循环consumer.recieve()方法来实现监听。

 

 事实上一个消费者对应了一个AsyncMessageListenerInvoker任务,每个任务需要一个单独的线程去执行它。这个AsyncMessageListenerInvoker实例被放在了一个名为scheduledInvokers的set里面。

 其实我们还有一个比较关心的地方是这个DefaultMessageListenerContainer缓不缓存connection,session,consumer。它是根据catchLevel属性来决定是否缓存connection,session,consumer。默认的catchLevel对应常量CATCH_AUTO,即由配置的外部事务管理器决定。catchLevel级别分别是CATCH_NONE,CATCH_CONNECTION,CATCH_SESSION,CATCH_CONSUMER,分别对应0,1,2,3。我试了下默认的CATCH_AUTO在没有定义事务管理时值为 CATCH_CONSUMER,即3。

 DefaultMessageListenerContainer会根据catchLevel来缓存共享connection,session,及consumer。值为3的话就会缓存connection,session,及consumer,在初始化的时候就会调用父类AbstractJmsListeningContainer的doStart()方法,判断cacheLevel是否大于等于1,如果大于就创建一个connection将放入成员变量sharedConnection中。

  每个任务被执行的时候(即责任是监听消息),会先去获取connection,session及consumer(通过调用initResourcesIfNecessary方法)就像我们自己最初实现一个简单的客户端消费者一样。只不过这里会根据catchLevel来决定是否缓存session及consumer。被缓存了的session及consumer放在对应的成员变量里面。

 接着任务会想要执行consumer.recieve方法,这之前肯定要获取onnection,session及consumer,如果已有onnection,session及consumer则获取过来,如果没有则通过配置的信息新建。执行完consumer.recieve后,会判断consumer.recieve返回的消息是否为空。

  不为空则调用message对应的messageListner(之前我们在DefaultMessageListenerContainer中通过方法setMessageListner设置的)的onMessage执行相应的逻辑,并设置这个任务的Idle为false,表明这个任务不是空闲的,然后会调用方法判断是否应该新建任务实例,这个受限于MaxConcurrentConsumersIdleTaskExecutionLimit。为空则不需要特别处理,只需调用noMessageReceived方法将idle标记设为true。

  任务执行完后,会在finally处释放connection,session及consumer。这个是根据上述讲的catchLevel来设置的。


  继承体系如下:

   

 
AbstractJmsListeningContainer提供了一个最上层最基础的jms消息监听管理类所应该有的方法。提供了start(启动这个管理类),stop,initialize(初始化这个管理类),establishSharedConnection等。


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要动态创建多个DefaultMessageListenerContainer实例,并启动监听,可以使用Spring的@Autowired注解来注入一个JmsListenerEndpointRegistry实例,并使用它来创建和管理各个监听器容器实例。 首先,在你的Spring配置类中注入JmsListenerEndpointRegistry实例: ``` @Configuration @EnableJms public class AppConfig { @Autowired private JmsListenerEndpointRegistry endpointRegistry; // ... } ``` 然后,你可以编写一个方法来动态创建和注册一个DefaultMessageListenerContainer实例,并将其添加到JmsListenerEndpointRegistry中: ``` public void createListenerContainer(String destinationName, MessageListener messageListener) { DefaultMessageListenerContainer container = new DefaultMessageListenerContainer(); container.setConnectionFactory(connectionFactory()); container.setDestinationName(destinationName); container.setMessageListener(messageListener); container.afterPropertiesSet(); endpointRegistry.registerListenerContainer(new MethodJmsListenerEndpoint(messageListener, container)); } ``` 在这个方法中,我们创建了一个DefaultMessageListenerContainer实例,并设置了连接工厂、目的地名称和消息监听器。然后,我们将其添加到JmsListenerEndpointRegistry中,使用MethodJmsListenerEndpoint来包装它,并将消息监听器与之关联。 最后,你可以在需要的时候调用这个方法来创建和启动新的监听器容器实例: ``` createListenerContainer("queue1", myMessageListener1); createListenerContainer("queue2", myMessageListener2); ``` 当你想要停止监听器容器时,可以使用JmsListenerEndpointRegistry的unregister方法来注销它: ``` endpointRegistry.unregister(listenerEndpoint); ``` 其中listenerEndpoint是在注册监听器容器时使用的MethodJmsListenerEndpoint实例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值