【问题标题】:Using Control bus to stop message-driven-channel-adapter that uses transactional session使用控制总线停止使用事务会话的消息驱动通道适配器
【发布时间】:2013-12-26 16:48:33
【问题描述】:

我的要求是使用带有消息驱动通道适配器 (JmsMessageDrivenEndpoint) 的事务会话。我可以使用 sessionTransacted = true 为 DefaultMessageListenerContainer 设置配置购买。

工作流程:接收消息->调用服务激活器->服务激活器调用dao类

成功提交到数据库时,spring 框架会调用 commit(),而在任何运行时异常时,spring 框架会调用 rollback()。哪个工作得很好。当发生回滚时,JMS 代理将消息再次发送回我的应用程序。

对于 dao 中的特定类型的异常,我想添加消息头(即重新发送时间),以便 JMS Broker 不会立即再次发送消息。我该怎么做?

对于 dao 中的另一种特定类型的异常,我想使用控制总线停止端点(消息驱动通道适配器)并在停止它之前回滚前一个事务。我该怎么做?

谁能帮帮我?

【问题讨论】:

    标签: spring-integration spring-transactions spring-jms


    【解决方案1】:

    难怪如何使用控制总线来启动/停止端点:

    <int:control-bus input-channel="controlChannel"/>
    
    <int-jms:message-driven-channel-adapter id="jmsInboundEndpoint"/>
    
    <int:transformer input-channel="stopImsInboundEndpointChannel"
               outbound-channel="controlChannel"
               expression="'@jmsInboundEndpoint.stop()'"/>
    

    或者您可以从代码的任何位置向controlChannel 发送相同的命令字符串。

    但是最后一个事务是否会被回滚并不重要。这取决于您的“工作单元”(换句话说 - 您的服务的行为)。

    但是,您可以在发送“停止命令”的同时,将当前事务标记为回滚:

    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    

    关于“添加一些消息标题”的另一个问题对于消息传递来说是不正常的。 如果您更改消息,它将是一条新消息,并且您无法使用一些新信息将消息回滚到队列中。

    当然,您无论如何都可以这样做并获得新消息。但是你应该resend 它,而不是回滚。因此,无论如何,您都应该提交事务并将新消息发送到某处(或同一队列),但对于 Broker 以及您的应用程序来说,它将是新消息。还有一次:对于这种情况,您必须提交事务。

    不确定是否很清楚,我的回答是正确的,但希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      您不能在回滚之前修改消息(添加标头)。当然,您可以在捕获异常后将其作为新消息重新排队。一些代理(例如 ActiveMQ)在回滚后提供回退重试策略。如果您的经纪人支持,这可能是一个更好的解决方案。

      您可以使用控制总线来停止容器,但您可能必须异步执行此操作(在另一个线程上调用停止,例如通过在控制总线上使用 ExecutorChannel)。否则,根据您的环境,您可能会遇到停止等待容器线程退出的问题,因此您不应在容器线程本身上执行停止。

      最好的办法是实验。

      【讨论】:

      • 嗨,加里:感谢您的回复。根据@Artem 的建议,如果我将当前事务(JMS 事务)标记为 rollbackOnly,它将与您异步调用 stop() 的建议一起使用吗?顺便说一句,我正在使用专有的 JMS 代理,并且还没有用于我的测试的 JNDI 设置。设置好 JNDI 后,我将进行实验
      • 因为它(可能)需要异步完成,您可能会遇到一个竞争条件,即在 stop() 完成之前发生回滚,您可能会收到另一个交付。这就是为什么我建议在同步停止和异步停止之间进行试验。
      【解决方案3】:

      感谢 Gary 和 Artem。解决方案正在发挥作用。我正在使用以下配置:

      <jms:message-driven-channel-adapter id="jmsMessageDrivenChannelAdapter" connection-factory="connectionFactory"
              destination="destination" transaction-manager="jmsTransactionManager" channel="serviceChannel" error-channel="ultimateErrorChannel" />
      <si:service-activator input-channel="ultimateErrorChannel" output-channel="controlChannel">
          <bean class="play.spring.integration.TestErrorHandler">
              <property name="adapterNeedToStop" value="jmsMessageDrivenChannelAdapter" />
              <property name="exceptionWhenNeedToStop" value="play.spring.integration.ShutdownException" />
          </bean>
      </si:service-activator>
      <si:channel id="controlChannel">
          <si:dispatcher task-executor="controlBusExecutor" />
      </si:channel>
      <task:executor id='controlBusExecutor' pool-size='10' queue-capacity='50' />
      <si:control-bus input-channel="controlChannel" />
      

      现在我的问题是,如果我想停止多个入站适配器,如何向所有这些适配器的控制总线发送一条消息?

      我要学习SpEL。如果有人已经知道,将不胜感激。

      谢谢

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-15
        • 2016-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-04
        相关资源
        最近更新 更多