spring-jms源码窥探一二

该文档是通过adoc文件转化而来,格式有所欠佳,请见谅。
该篇博客后期可能会继续完善,未完待续o( ̄︶ ̄)o

该文档主要从3方面来讲述spring-jms的内容:

  1. 资源方面,
    如JMS的Connection、session、consumer、producer等,spring主要通过SingleConnectionFactory和CachingConnectionFactory实现。

  2. 工具类方面, spring提供了同使用数据库JdbcTemplate一样简易的工具类JmsTemplate.

  3. 消息驱动编程(MDBs)方法,
    spring主要通过SimpleMessageListenerContainer和DefaultMessageListenerContainer来实现。

connection

Figure 1.ConnectionFactory

SingleConnectionFactory

  1. 只维护了一个连接

    • CachingConneciontFactory维护的Session也是连接,从ibm的jms实现来看

    • ibm jms的不同版本的实现不一样,9.1.0.3创建Session不会创建连接,
      9.1.3.0创建Session会创建连接。

  2. AggregateExceptionListener维护了连接异常处理链

    • SingleConnectionFactory
      自身就实现了ExceptionListener接口,会添加到处理链上。

    • SCF
      自身也提供了setExceptionListener接口,供用户自定义异常处理,添加到处理链上。

  3. SharedConnectionInvocationHandler 实现了对Connection的代理

    • 代理createSession的时候会调用getSession方法

      • CachingConnectionFactory会实现该方法,返回缓存的Session,如果缓存到达SessionCacheSize会生成新的Session。

      • SingleConnectionFactory每次都会重新创建Session

  4. 实现了DisposableBean接口为优雅停机提供了支持

    • resetConnection()
      方法主要实现了对持有的Connection进行stop和close

CachingConnectionFactory

从Figure 1.ConnectionFactory图中可以看出CachingConnectionFactory主要对SingleConnectionFactory进行了功能的扩展。

  1. CCF 支持缓存Session, Producer, Consumer

    • Producer, Consumer的缓存是挂在Session下面
  2. CCF实现了异常重连

  3. CachedSessionInvocationHandler实现了对缓存Session的代理。

    • close方法代理:
      如果缓存的Session数量没达到最大的值,就执行逻辑关闭,并添加到缓存的集合;
      如果达到了,就执行物理关闭。

    • 代理的创建Producer和Consumer的方法,对应的方法会缓存创建出来的对象。

  4. Override了父类SingleConnectionFactory的 resetConnection()方法

    • 在父类关闭Connection的基础上,添加了关闭Session和Consumer、Producer的功能。

JmsTemplate

Figure 2.JmsTemplate

从Figure 2.JmsTemplate图中可以看出,JmsTemplate主要实现了两个分支的功能。

JmsOperations接口(JmsTemplate主要实现的功能)

  1. 定义了通用的jms操作,如 send、receive等方法。

JmsAccessor抽象类(没有抽象方法)

  1. 配置了访问jms的基础配置,如:
    ConnectionFactory、isSessionTransacted、SessionAcknowledgeMode、Jms异常转化、createConnection、createSession.

JmsDestinationAccessor抽象类(没有抽象方法)

  1. 基于JmsAccessor类的基础上添加了对Destination的支持,如:
    DestinationResolver、isPubSubDomain

JmsTemplate

  1. excecute方法

    • 主要实现了资源(connection,session)的获取和释放,类似JdbcTemplate.
      判断事务上下文中是否有存在的Session:如果有,就直接使用;如果没有,通过保存的ConnectionFactory进行创建Session(JmsAccessor的sessionTransacted默认为false,所以不需要进行提交)。

    • 使用获取到的资源执行 SessionCallback接口

    • 关闭资源:如果是事物的Session不需要关闭/归还如果不是事务的Session需要归还

小结

  1. 针对JmsTemplate来说,对应的Connection、Session是在需要的时候才创建的。

  2. 需要的资源主要靠各个ConnectionFactory提供的资源缓存功能来支持。

MessageListenerContainer

Figure 3. ListenerContainer

从图Figure 3. ListenerContainer的最左边来看是和JmsTemplate是一条路线的

MessageListenerContainer(其中的方法都未实现)

  1. extends生命周期接口SmartLifecycle

  2. 包含了设置和获取MessageConverter和DestinationResolver(JmsDestinationAccessor中也有)的途径

AbstractJmsListeningContainer

官方doc说明:

  • 该类提供基本的生命周期管理,特别是共享JMS连接的管理。子类应该插入到这个生命周期中,实现sharedConnectionEnabled()以及doInitialize()和doShutdown()模板方法。

  • 此基类不假设任何特定的侦听器编程模型或侦听器调用程序机制。它只提供在JMS
    Connection/Session上操作的任何基于JMS的侦听机制所需的通用运行时生命周期管理。

  • 要了解具体的侦听器编程模型(listener programming),请查看
    AbstractMessageListenerContainer
    子类。要了解具体的侦听器调用器机制(listener invoker),请查看DefaultMessageListenerContainer类。

SmartLifecycle

  1. start()

    • 创建共享连接; 回复暂停任务; 启动共享连接
  2. stop()

    • 停止共享连接
  3. isAutoStartup()

    • 默认为true
  4. getPhase()

    • 默认值 ==== DisposableBean
  5. destroy()

    • 停止共享连接

    • 停止invokers(由各子类实现,DefaulMessageListenerContainer,
      SimpleMessageListenerContainer)

重要方法

  1. afterPropertiesSet中的initialize的方法

    • 在这个方法中会调用doInitialize()方法, doInitialize方法:

      • 在此容器中注册所有调用程序(invokers)。

      • 子类(DefaulMessageListenerContainer,
        SimpleMessageListenerContainer)需要为其特定的调用者管理过程实现此方法。

  2. rescheduleTaskIfNecessary(具体实现)
    获取给定的任务对象并重新调度它,如果容器当前正在运行,可以立即进行调度,或者在容器重新启动后进行调度。

    • 这个方法会执行方法
      doRescheduleTask方法(由具体需要rescheduleTaskIfNecessary的子类来实现),

    • DefaultMessageListenerContainer 的 doInitiallize()-→初始化
      concurrentConsumres 数量的 AsyncMessageListenerInvokers
      scheduleNewInvoker()-→ rescheduleTaskIfNecessary -→
      doRescheduleTask() 将invokers 交付给taskExecutor执行。
      即所谓的listener invokder机制

  3. resumePausedTasks方法,恢复暂停任务

AbstractMessageListenerContainer

Spring消息侦听器容器实现的抽象基类。可以承载标准JMS
MessageListener或Spring的SessionAwareMessageListener进行实际的消息处理。

提供了设置MessageListener的功能, 为上层接口
SimpleMessageListenerContaier和DefaultMessageListenerContainer提供了执行
MessageListener的公共方法方法。

处理了在执行Listener过程中的模板步骤,如commit/rollback

重要方法

  1. doExecuteListener 执行指定的侦听器,然后提交或回滚事务(如果需要)。

  2. invokeListener(Sessioin,Message)
    根据容器的Listener类型(SessionAwareMessageListener/MessageListener)调用不同的方法执行。

SimpleMessageListenerContainer

消息侦听器容器,它使用普通JMS客户机API的MessageConsumer.setMessageListener()方法为指定的侦听器创建并发messageconsumer。

这是消息侦听器容器的最简单形式。它创建固定数量的JMS会话来调用侦听器,不允许动态地适应运行时需求。它的主要优点是其较低的复杂性和对JMS提供者的最低要求:甚至不需要ServerSessionPool功能。

有关确认模式和事务选项的详细信息,请参阅AbstractMessageListenerContainer
javadoc。请注意,此容器公开了默认“AUTO_ACKNOWLEDGE”模式的标准JMS行为:即,在侦听器执行后自动确认消息,在抛出用户异常的情况下不进行重新交付,但在侦听器执行期间JVM死亡的情况下可能进行重新交付。(因为沿用了JmsAccessor的默认配置,sessionTransacted=false,
sessionAcknowledgeMode=Session.AUTO_ACKNOWLEDGE)

SimpleMessageListenerContainer主要实现了AbstractMessageListenerContainer的模板办法

主要实现的模板方法

  1. doInitialize

    • 建立共享连接

    • 初始化消费者

      • 根据concurrentConsumers的配置生成对应个数的Session,
        MessageConsumer对象,已提供并发消费消息;
        并设置MessageConsumer的MessageListener进行消息异步消费,在消费的过程会回调到AbstractmessageListenerContainer的doExecuteListener方法。

如果给SimpleMessageListenerContainer设置了TaskExecutor,
任务将在新的线程中执行,会影响acknowledgement的使用,消息总是在侦听器执行之前得到确认,并立即重用底层会话以接收下一条消息。

AbstractPollingMessageListenerContainer

基于轮询的侦听器容器实现的基类。提供基于MessageConsumer的侦听器处理支持,可选地参与外部管理的事务。

此侦听器容器变体是为重复轮询尝试而构建的,每次都调用 receiveAndExecute
方法。使用的
MessageConsumer可能会被重新获取以进行访问尝试或在两次尝试之间缓存;这取决于具体的实施。每次尝试的接收超时可以通过“
receiveTimeout ”属性配置。

底层机制基于标准JMS MessageConsumer处理,它与Java
EE环境中的本机JMS和JMS完全兼容。也不是JMS
MessageConsumer.setMessageListener设施而不是JMS
ServerSessionPool设施是必需的。这种方法的另一个优点是完全控制侦听过程,允许自定义缩放和节流以及并发消息处理(这取决于具体的子类)。

通过将springplatformtransactionmanager传递到“transactionManager”属性中,消息接收和监听器执行可以自动封装在事务中。这通常是Java
EE环境中的org.springframework.transaction.jta.JtaTransactionManager,结合从JNDI获得的jta感知JMS
ConnectionFactory(请查看应用服务器的文档)。

此基类不假设轮询调用程序的异步执行有任何特定机制。查看DefaultMessageListenerContainer的具体实现,它基于Spring的org.springframework.core.task.TaskExecutor抽象,包括并发消费者的动态伸缩和自动自恢复

主要实现的方法

  1. 覆盖@Override AbstractJmsListeningContainer的initialize()方法

    • 在非jta事务管理器的情况下,设置sessiontransaction =true。

    • 调用父类的 initialize方法,sup.initialize(),
      为了回调父类中的doInitialize的调用(个子类实现doInitialize的模板方法进行初始化invokers)

      • SimpleMessageListenerContainer根据concurrentConsumers初始化了对应的Consumer对象,并进行了MessageListener的设置,进行消息的并发消费

      • DefaultmessageListenerContainer根据concurrentConsumer初始化了对应的线程数,线程的任务是AsyncMessageListenerInvoker。

  2. doReceiveAndExecute
    (invokder,session,MessageConsumer,TransactionStatus)

    • 其中的receiveMessage(consumerToUse)方法,使用了JMS的MessageConsumer的receive(timeout)接口来接收invoker的消息。

      • 【如果收到消息】

        • 调用模板方法(未实现) messageReceived(invoker,session):
          模板方法,该方法在接收到新消息后,在尝试处理它之前立即调用。允许子类对实际传入消息的事件做出反应,例如调整它们的消费者计数

          • DefaultMessageListenerContainer实现了该方法:
            设置当前invoker(AsyncMessageListenerInvoker)为非空闲(idle=false);
            调用scheduleNewInvokerIfAppropriate()方法进行invoker数量的调整。
        • 并使用事务工具将Session给暴露出去,可以供Listener中
          JmsTemplate使用,达到事务控制的功能。

        • 执行 AbstractMessageListenerContainer的
          doExecuteListener(sessionToUse,message)(包含了事务的管理,如回滚和提交)

      • 【如果没收到消息】

        • 调用模板方法(未实现)
          noMessageReceived(invoker,sessionToUser)
    • 重点:这个方法不会归还重CachingConnectionFactory借出来的Session和MessageConsumer

DefaultMessageListenerContainer

主要实现的方法

  1. initialize 模板方法

    • 如果没有transactionManager设置cacheLevel为3(CACHE_CONSUMER)

    • 创建TaskExecutor,类型为SimpleAsyncTaskExecutor,线程前缀名为DefaultMessageListenerContainer-

    • 调用父类
      AbstractPollingMessageListenerContainer的initialize()方法

      • 调用父类的AbstractJmsListeningContainer的initiallize()方法,当前的initiallize方法会回调到子类的doInitialize()方法
    • 调用DefaultMessageListenerContainer的doInitialzie()方法

      • 根据 concurrentConsumers 数量的配置来创建对应个数的
        AsyncMessageListenerInvoker 对象

AsyncMessageListenerInvoker 内部类对象

循环执行MessageConsumer.receive()的程序类。它主要分为两种情况:
maxMessagesPerTask 是否大于。

  1. maxMessagePerTask小于0的情况

    • 调用executeOngoingLoop方法,改方法主要通过while一直执行调用

      • 调用 invokeListener()方法;

        • 通过调用
          iniResourceIfNecessary()进行Session和Consumer的初始化(如果还未初始化);

        • 通过调用
          AbstractPoolingMessageListenerContainer.receiveAndExecute(self-invoker,
          session,consumer) 进行消息处理,对应的回调用
          doReceiveAndExecute 方法,请参考APMLC的说明。

spring boot(mq-jms-spring-boot-starter-2.2.0)相关

MQConnectionFactoryConfiguration 配置类

  1. cachingJmsConnectionFactory 方法创建 spring CachingConnectionFactory

    • 设置了 cacheConsumers=false, cacheProducers=true,
      sessionCacheSize=1

JmsAnnotationDrivenConfiguration 配置类

  1. jmsListenerContainerFactory方法创建了DefaultJmsListenerContainerFactory

    • 设置了 sessionTransacted=true, autoStartup=true,
      receiveTimeout=30s

彩蛋

  1. 通过上面的描述,可以看出JmsTemplate的sessionTransacted是false,
    DefaultMessageListenerContainer的sessionTransacted是ture。
    请问他们在共用一个CachingConnectionFactory的时候为什么共享的Session不会窜用(如JmsTemplate用了DMLC创建出来的的transacted的Session,反之DMLC使用了JmsTemplate非transacted的Session).

    • 因为DMLC的Session是在Bean的afterPropertiesSet的声明周期创建的,而且创建出来的session不会归还到CachingConnectionFactory中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值