在之前的章节中,特别是《消费者本地事务》我们并没有进行任何配置,为什么事务生效了呢(不考虑关系型数据库的结合,结合后MQ事务仍然生效,但关系型数据库事务没有作为整体事务管理),下面我们通过对源码的分析来探索Spring如何帮助我们实现了。
本章概要
1、JmsListener注解解析
2、其他消费方式实现(3种)
3、分布式事务的支持
JmsListener注解解析
1、通过JmsListener注解监听消费,实现了异步消费;
2、在官方文档中已经说明需要支持@JmsListener注解,则需要在任意@Configuration类添加@EnableJms注解,同时还需要配置
DefaultJmsListenerContainerFactory 的Bean实例,如下
在springboot中通过JmsAnnotationDrivenConfiguration对相关bean实例实现注册。在注册的DefaultJmsListenerContainerFactoryConfigurer中可以发现其支持JTA分布式事务管理,以及DefaultJmsListenerContainerFactoryConfigurer中的configure方法能够看到如下代码:
if (this.transactionManager != null) {
factory.setTransactionManager(this.transactionManager);
} else {
factory.setSessionTransacted(Boolean.valueOf(true));
}
在没有配置外部事务管理器时默认支持jms内部的session事务机制,这也就很好的解释了为什么在@JmsListener注解下的消费者本地事务在没有进行任何配置的情况下已经生效,甚至能够很好的将消息的消费与生产在一个事务中有效处理。
继续往下看源码,在DefaultJmsListenerContainerFactory中定义了创建了DefaultMessageListenerContainer消息监听容器,后续很多监听参数的设置均对其设置即可(如durableSubscriptionName支持持久化订阅);
而DefaultJmsListenerContainerFactory继承于AbstractJmsListenerContainerFactory,其中定义了真正创建DefaultMessageListenerContainer对象的方法
public C
createListenerContainer(JmsListenerEndpoint endpoint) {
AbstractMessageListenerContainer instance =
createContainerInstance();
........
endpoint.setupListenerContainer(instance);
initializeContainer(instance);
return instance;
}
protected abstract C createContainerInstance();
protected void initializeContainer(C instance) {
}
问题来了,spring是何时调用了
createListenerContainer方法创建了DefaultMessageListenerContainer呢,在JmsListenerEndpointRegistrar有如下几个方法定义
其中resolveContainerFactory获取在JmsAnnotationDrivenConfiguration注册的DefaultJmsListenerContainerFactory,提供register**方法注册对应的端点,
继续跟踪this.endpointRegistry.registerListenerContainer(descriptor.endpoint,resolveContainerFactory(descriptor));方法,其实现在JmsListenerEndpointRegistry中,
红色标示部分可以看到我们正是通过之前获取的DefaultJmsListenerContainerFactory调用
createListenerContainer方法定义了最终的消息监听容器
DefaultMessageListenerContainer。到这里其实还没有结束,继续往下找最终的消息监听事件处理在MessageListenerAdapter中的onMessage-->invokeListenerMethod方法执行处理。
以上是java配置方式,我们也可以通过XML配置,来源官网截图:
其他消费方式
方式一,从官方可以看到下面的描述,如果我们不使用@JmsListener注解进行消息的消费监听,可以在编码中通过JmsListenerEndpoint配置JmsListenerConfigurer替代@JmsListener
spring提供了SimpleJmsListenerEndpoint协助我们进行配置,JmsListenerEndpointRegistrar在上述@JmsListener也有所涉及,最重要的还是endpoint.setMessageListener(message -> { // processing});
最终消息的监听处理在我们定义的MessageListener中实现。
我们需要定义消息监听MessageListener的实现类,其有3中实现方式:MessageListener、SessionAwareMessageListener和MessageListenerAdapter。
1、MessageListener:实现异步监听,通过onMessage方法处理唯一参数Message。MessageListener的设计只是纯粹用来接收消息的,假如我们在使用MessageListener处理接收到的消息时我们需要发送一个消息通知对方我们已经收到这个消息了,那么这个时候我们就需要在代码里面去重新获取一个Connection或Session;
2、SessionAwareMessageListener:SessionAwareMessageListener是Spring为我们提供的,它不是标准的JMS MessageListener。SessionAwareMessageListener的设计就是为了方便我们在接收到消息后发送一个