JMS Poller Transactional

时间:2016-05-04 03:33:14

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

我正在使用Spring Integration 4.1.5并试图对事务做些什么,但遗憾的是我无法找到工作示例。我正在尝试设置正在查找消息的JMS轮询器。收到消息后,服务激活器会在数据库中插入一行,并将消息传递给另一个服务激活器。我想制作前两部分,信息提取和放大器。数据库插入事务。我不希望其余的流程是事务性的。我使用Weblogic作为应用程序容器,因此将使用WebLogicJtaTransactionManager。

我遇到的问题是我无法将前两件事交易。它全部或全部都没有。我尝试了很多方法,但我觉得在轮询器上使用建议链是最好的选择。我将能够控制哪些方法将成为交易的一部分。

我已经看过使用消息驱动监听器的示例,但我使用的是Weblogic并且将使用工作管理器,我相信我必须使用轮询器才能利用工作经理(如果这样做'事实并非如此,我想这是未来的另一个问题!)

我已经使用了xml并对其进行了简化,但除了编辑包名外,上下文也会产生问题。

   <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:file="http://www.springframework.org/schema/integration/file"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
    xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
    xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/integration 
    http://www.springframework.org/schema/integration/spring-integration.xsd 
    http://www.springframework.org/schema/integration/file 
    http://www.springframework.org/schema/integration/file/spring-integration-file.xsd 
    http://www.springframework.org/schema/integration/sftp 
    http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/integration/xml 
    http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd 
    http://www.springframework.org/schema/integration/jms 
    http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="jtaTransactionManager"
        class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
        <property name="transactionManagerName" value="javax.transaction.TransactionManager" />
    </bean>

    <bean id="insertMessageToDb" class="com.ReadMsgFromAxway" />
    <bean id="serviceActivator" class="com.CreateTMDFile" />

    <int-jms:inbound-channel-adapter id="jmsDefaultReceiver"
        connection-factory="inboundDefaultAdaptorConnectionFactory"
        extract-payload="false" destination="inboundAdaptorDefaultListenerQueue"
        channel="inboundJMS" acknowledge="transacted">  
        <int:poller id="poller" 
            max-messages-per-poll="100" fixed-rate="10">
            <int:advice-chain>
                <ref bean="txAdvice" />
            </int:advice-chain>
        </int:poller>
    </int-jms:inbound-channel-adapter>


    <tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">
        <tx:attributes>
            <tx:method name="processMessage" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="txOperation" 
            expression="execution(* axway.ReadMsgFromAxway.processMessage(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txOperation" />
    </aop:config> 

    <int:service-activator input-channel="inboundJMS"
        output-channel="serviceActivatorChannel" ref="insertMessageToDb" method="processMessage" />

    <int:chain input-channel="serviceActivatorChannel" output-channel="nullChannel">
        <int:service-activator ref="serviceActivator" />
    </int:chain>

</beans>

ReadMsgFromAxway.java

    public Message<File> processMessage(Message<?> message)  {
//Insert into DB
        trackerProcess.insertUpdateMessageTracker(message, "axwayChannel",
                "axwayChannel", currentStatusID, null, null);
        count++;
        int mod = count % 2;
        if (mod != 0) {
            // pass every 2
            String hello = "hey";
        } else {
            throw new RuntimeException("Testing transactional");
        }

        Message<File> springMessage = MessageBuilder.createMessage(payloadFile,
                messageHeaders);
        return springMessage;
    }

XML不会做任何事情,无论是抛出运行时异常,还是在下一个服务激活器组件抛出异常。

如果我将建议属性更改为

        <tx:method name="*" propagation="REQUIRED"/>

然后,第一个和第二个服务激活器的异常导致回滚。

奇怪的是,如果我这样做

        <tx:method name="processMessage" propagation="REQUIRED"/>
        <tx:method name="*" propagation="NEVER"/>

然后,是否抛出第一个服务激活器或第二个激活器中的运行时异常,消息将被回滚。我认为切入点会限制哪个类会导致交易,但我可能会误解某些内容。

另一个注意事项 - 这个应用程序存放在一个带有其他几个战争的耳朵文件中。此上下文启动整个入站进程,并通过JMS队列连接到包含业务逻辑的另一个war。在使用方法名称=&#34; *&#34;的方案中我在业务逻辑战中看到了异常,导致原始入站消息的JMS消息也被回滚。我的印象是第二次战争将在另一个线程中进行处理,因为它通过队列接收消息,因此不属于事务的一部分。这可能是JTA的副作用,它是容器管理的吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

我建议您阅读Dave Syer的article关于交易的内容,您可以在&#34;更多内容中找到一个链接&#34;。

现在看起来你根本不了解交易和AOP。您应该更加关注Spring Framework中的AOP支持。

一般来说,声明式事务(方法@Transactional)是AOP建议的特例。任何AOP背后的主要概念是由方法调用产生的调用堆栈边界,我们为其指定了一个建议。

但是如果目标对象中没有这样的方法,它就不会被建议并包装到AOP代理中。与您processMessage的情况类似,当您将txAdvice应用于org.springframework.messaging.Message.MessageSource周围的某个内部对象作为JmsDestinationPollingSource的{​​{1}}合约时。{ / p>

相反,您可以使用<int-jms:inbound-channel-adapter>的{​​{1}}配置。正确:所有的下游流程都将由交易覆盖。

在这种情况下为内部

完成交易
<transactional>

<poller> Callable<Boolean> pollingTask = new Callable<Boolean>() { @Override public Boolean call() throws Exception { return doPoll(); } }; 附近,您应该像常规receive()一样完成方法调用。为此,我们应该将下一个消息处理到另一个线程。只是因为默认情况下所有handleMessage()都是@Transactional并且与当前调用堆栈绑定。

为此,您可以<channel>使用DirectChannelExecutorChannel)。

从那里你不需要其余的AOP配置。

不确定您的其他网络应用的第二个问题。看起来它有一些逻辑可以挽回它的工作,以防你身边出现一些不一致的情况。但无论如何,这看起来像是一个不同的问题。