这是我的第一篇文章,所以希望我不会把格式搞得太糟糕。
我有一个Spring集成路由,它按如下方式路由消息:
网关 - >路由器 - > outbound-jms-channel - >消息驱动频道 - >服务活化剂
我正在使用spring集成版本4.0.3和activemq版本5.10.0。在这个特定的实例中,我在weblogic容器中运行(虽然情况并非总是如此)。
路由是将JMS消息发布到activemq队列。如果在执行侦听器期间遇到运行时异常,我希望回滚在侦听器中登记的任何事务资源以及重新传递消息。目前我看到回滚但没有重新传递消息。
我的弹簧配置如下:
<!-- TaskExecutor is defined elsewhere and is our own object, it's effectively the equivalent of calling Executors.newCachedThreadPool(). -->
<bean id="TransactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>
<bean id="XADataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${xaJndiName}"/>
</bean>
<amq:broker brokerName="messageBroker" useJmx="true" persistent="true" start="true" schedulerSupport="false">
<amq:transportConnectors>
<amq:transportConnector id="tcpConnector" uri="tcp://garethDell.leeds.retailexp.com:9783"/>
</amq:transportConnectors>
<amq:persistenceAdapter>
<amq:jdbcPersistenceAdapter dataSource="#XADataSource"/>
</amq:persistenceAdapter>
</amq:broker>
<amq:xaConnectionFactory id="amqConnectionFactory" brokerURL="tcp://garethDell.leeds.retailexp.com:9783" useAsyncSend="false">
<amq:prefetchPolicy>
<amq:prefetchPolicy all="1"/>
</amq:prefetchPolicy>
<amq:redeliveryPolicy>
<amq:redeliveryPolicy id="redeliveryPolicy" initialRedeliveryDelay="5000" maximumRedeliveries="5" useExponentialBackOff="true" backOffMultiplier="2" queue="*" />
</amq:redeliveryPolicy>
</amq:xaConnectionFactory>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"/>
<property name="reconnectOnException" value="true"/>
</bean>
<int:gateway id="messageGateway" service-interface="com.retailexp.amp.server.spring.MessageGateway" default-request-channel="requestChannel"/>
<bean id="MessagePublisher" class="com.retailexp.amp.server.common.publishing.impl.MessagePublisher">
<property name="gateway" ref="messageGateway"/>
</bean>
<!-- Routes the messages to the appropriate destination, each queue / topic should have an appropriate channel associated with it which must be registered here-->
<int:channel id="requestChannel"/>
<int:header-value-router id="destinationRouter" input-channel="requestChannel" header-name="destination">
<int:mapping value="test" channel="testOutChannel"/>
</int:header-value-router>
<int:channel id="testOutChannel"/>
<int-jms:outbound-channel-adapter id="testOut" channel="testOutChannel" connection-factory="connectionFactory" destination="testQueue"/>
<int:channel id="testListener"/>
<int-jms:message-driven-channel-adapter id="testIn" connection-factory="connectionFactory" container="testQueueContainer" channel="testListener"/>
<!-- Define the queues -->
<bean id="testQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="test"/>
</bean>
<!-- Define the message listeners -->
<bean id="testMessageHandler" class="com.retailexp.amp.server.spring.TestListener"/>
<int:service-activator input-channel="testListener" ref="testMessageHandler" method="onMessage"/>
<bean id="testQueueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="transactionManager" ref="TransactionManager"/>
<property name="taskExecutor" ref="TaskExecutor"/>
<property name="maxConcurrentConsumers" value="10"/>
<property name="sessionTransacted" value="true"/>
<property name="sessionAcknowledgeMode" value="0"/>
<property name="destination" ref="testQueue"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
</bean>
我的监听器在这个阶段非常直接,它会注销消息,然后保存我们的一个域对象,最后抛出一个运行时异常来强制回滚。此阶段的回滚显示在日志中,并且数据库更改已正确回滚,因此我知道在侦听器中我将获得事务回滚。我假设消费者不应该作为XA事务的一部分参与,因此消息的消费是作为单独事务的一部分提交的(在某种程度上是非事务性的?)。
由于TransactionContext中的xa jdbc驱动程序,我看到设置事务隔离级别的错误,但我不认为这是问题的原因 - 我尝试使用各种不同的隔离级别,例如8 TRANSACTION_SERIALIZABLE所以我认为这仅仅是驱动程序本身的限制。
例外:
[11 Sep 2014 16:53:07,464] [ActiveMQ Transport: tcp:///192.168.50.100:58292@9783 ] [ ] [ ] TRACE jdbc.TransactionContext - Cannot set transaction isolation to 1 due Due to vendor limitations, setting transaction isolation for "Oracle XA" JDBC XA driver is not supported.. This exception is ignored.
java.sql.SQLException: Due to vendor limitations, setting transaction isolation for "Oracle XA" JDBC XA driver is not supported.
at weblogic.jdbc.wrapper.JTAConnection.setTransactionIsolation(JTAConnection.java:492)
at org.apache.activemq.store.jdbc.TransactionContext.getConnection(TransactionContext.java:74)
at org.apache.activemq.store.jdbc.adapter.DefaultJDBCAdapter.doAddMessage(DefaultJDBCAdapter.java:220)
at org.apache.activemq.store.jdbc.JDBCMessageStore.addMessage(JDBCMessageStore.java:126)
at org.apache.activemq.store.memory.MemoryTransactionStore.addMessage(MemoryTransactionStore.java:343)
at org.apache.activemq.store.memory.MemoryTransactionStore$1.asyncAddQueueMessage(MemoryTransactionStore.java:159)
at org.apache.activemq.broker.region.Queue.doMessageSend(Queue.java:910)
at org.apache.activemq.broker.region.Queue.send(Queue.java:733)
at org.apache.activemq.broker.region.AbstractRegion.send(AbstractRegion.java:424)
at org.apache.activemq.broker.region.RegionBroker.send(RegionBroker.java:445)
at org.apache.activemq.broker.jmx.ManagedRegionBroker.send(ManagedRegionBroker.java:297)
at org.apache.activemq.broker.BrokerFilter.send(BrokerFilter.java:147)
at org.apache.activemq.broker.CompositeDestinationBroker.send(CompositeDestinationBroker.java:96)
at org.apache.activemq.broker.TransactionBroker.send(TransactionBroker.java:307)
at org.apache.activemq.broker.MutableBrokerFilter.send(MutableBrokerFilter.java:152)
at org.apache.activemq.broker.TransportConnection.processMessage(TransportConnection.java:496)
at org.apache.activemq.command.ActiveMQMessage.visit(ActiveMQMessage.java:756)
at org.apache.activemq.broker.TransportConnection.service(TransportConnection.java:294)
at org.apache.activemq.broker.TransportConnection$1.onCommand(TransportConnection.java:148)
at org.apache.activemq.transport.MutexTransport.onCommand(MutexTransport.java:50)
at org.apache.activemq.transport.WireFormatNegotiator.onCommand(WireFormatNegotiator.java:113)
at org.apache.activemq.transport.AbstractInactivityMonitor.onCommand(AbstractInactivityMonitor.java:270)
at org.apache.activemq.transport.TransportSupport.doConsume(TransportSupport.java:83)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:214)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:196)
at java.lang.Thread.run(Thread.java:722)
我有跟踪级别的日志,如果需要它们是可用的,它们非常冗长,尽管如此推动我超过这篇文章的字符限制。让我知道他们是否有帮助,我会尽力让他们可以使用。
有人能看出上述配置是否有任何明显错误?
编辑:此处提供跟踪日志:http://pastebin.com/0awmzY2D
由于
答案 0 :(得分:1)
事实证明,在消息到达侦听器时,会话持有的TransactionContext上没有XID。实际上会话没有被加入到事务中,所以我得到了一个刚刚包含了监听器代码的新事务。
我做了一些关于招募应该在哪里发生的事情,看起来xa连接工厂在创建它时没有做任何事情来与事务进行对话,回想起来我是不知道为什么我认为它会因为它没有引用事务管理器。
更改为XAPooledConnectionFactory导致XaConnectionPool执行自动登记,配置更改如下:
<bean id="connectionFactory" class="org.apache.activemq.jms.pool.XaPooledConnectionFactory">
<property name="connectionFactory" ref="xaConnectionFactory"/>
<property name="tmJndiName" value="weblogic.transaction.TransactionManager"/>
<property name="tmFromJndi" value="true"/>
</bean>
<bean id="testQueueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="transactionManager" ref="TransactionManager"/>
<property name="taskExecutor" ref="TaskExecutor"/>
<property name="maxConcurrentConsumers" value="10"/>
<property name="sessionTransacted" value="true"/>
<property name="destination" ref="testQueue"/>
</bean>
我现在正在重新发送消息。我仍然遇到一个问题,即交付延迟和退出政策没有得到遵守(虽然奇怪的是最大的退款),但我确信我可以解决这个问题。
感谢您的时间。