Java Spring与JMS+的集成;ActiveMQ:重新连接后,消息仍保留在JDBC消息存储中
我正在尝试使用Spring集成和ActiveMQ消息代理配置JMS。我的出站通道应由JDBC消息存储支持,以防止数据丢失,例如代理或我的应用程序脱机 到目前为止,我的配置似乎工作正常,但是JDBC消息存储的行为与我预期的不同。如果我断开代理的连接,发送到出站通道的消息将按预期的方式持久化,但在重新连接之后,它们将保留在DB中,不会发送到队列。然而,我在重新连接后发送的更多消息到达队列,如果我重新启动应用程序,持久化的消息也将最终发送 应用程序上下文.xmlJava Spring与JMS+的集成;ActiveMQ:重新连接后,消息仍保留在JDBC消息存储中,java,activemq,spring-integration,spring-jms,Java,Activemq,Spring Integration,Spring Jms,我正在尝试使用Spring集成和ActiveMQ消息代理配置JMS。我的出站通道应由JDBC消息存储支持,以防止数据丢失,例如代理或我的应用程序脱机 到目前为止,我的配置似乎工作正常,但是JDBC消息存储的行为与我预期的不同。如果我断开代理的连接,发送到出站通道的消息将按预期的方式持久化,但在重新连接之后,它们将保留在DB中,不会发送到队列。然而,我在重新连接后发送的更多消息到达队列,如果我重新启动应用程序,持久化的消息也将最终发送 应用程序上下文.xml <?xml version="1
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:j2ee="http://www.springframework.org/schema/jee"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<!-- ActiveMQ Configuration -->
<jms:annotation-driven/>
<int:annotation-config/>
<!-- Factory for ActiveMQ connections from JNDI -->
<j2ee:jndi-lookup jndi-name="java:comp/env/jms/connectionFactory"
id="jmsConnectionFactory"
expected-type="org.apache.activemq.ActiveMQConnectionFactory"
proxy-interface="javax.jms.ConnectionFactory"
lookup-on-startup="false"
resource-ref="true"
cache="true"/>
<bean id="connectionFactory" class="org.apache.activemq.jms.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="maxConnections" value="8"/>
<property name="reconnectOnException" value="true"/>
</bean>
<!-- JAXB-marshaller from spring-oxm used to handle XML-payload of messages -->
<oxm:jaxb2-marshaller id="jax2bMarshaller" context-path="de.br.ecomx"/>
<!-- message-converter -->
<bean id="messageConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="jax2bMarshaller"/>
<property name="unmarshaller" ref="jax2bMarshaller"/>
</bean>
<!-- Message Store implementation -->
<!-- Persists messages temporariliy in DB to prevent data loss on server-shutdown -->
<!-- Has to be injected specifically in Queue Channels -->
<bean id="store" class="org.springframework.integration.jdbc.store.JdbcChannelMessageStore">
<property name="dataSource" ref="dataSource"/>
<property name="channelMessageStoreQueryProvider">
<bean id="queryProvider" class="org.springframework.integration.jdbc.store.channel.MySqlChannelMessageStoreQueryProvider"/>
</property>
<property name="usingIdCache" value="true"/>
<property name="region" value="BWH"/>
<property name="tablePrefix" value="BWH_"/>
</bean>
<!-- default poller for (non-message-driven) channel-adapters -->
<int:poller id="defaultPoller" default="true" fixed-delay="500">
<int:transactional propagation="REQUIRED" isolation="DEFAULT" transaction-manager="transactionManager"/>
</int:poller>
<!-- LOGGING -->
<!--<int:logging-channel-adapter id="logger" level="DEBUG" log-full-message="true"/>-->
<!-- CHANNEL DEFINITIONS -->
<!-- intermediate channel for message enrichment -->
<int:channel id="output_enricher_channel"><int:queue/></int:channel>
<!-- general output-channel - specific channel is choosed by a router -->
<int:channel id="output_router"><int:queue/></int:channel>
<!-- channel definitions connected to consumer queues -->
<int:channel id="bwh_articleMasterData_input_channel"><int:queue/></int:channel>
<int:channel id="bwh_transferOrder_input_channel"><int:queue/></int:channel>
<!-- add your channel here... -->
<!-- channel definitions connected to producer queues -->
<int:channel id="ax_transferOrderPacked_input_channel"><int:queue message-store="store"/></int:channel>
<!-- add your channel here... -->
<!-- MESSAGE HANDLING -->
<!-- Enriches the 'messageId'-property of payload with 'id'-value from header and sends them to router -->
<int:enricher input-channel="output_enricher_channel" output-channel="output_router">
<int:property name="messageId" expression="headers.id"/>
</int:enricher>
<!-- routing of outgoing messages to their type-specific channel -->
<int:payload-type-router input-channel="output_router">
<int:mapping type="de.br.ecomx.TransferOrdersPacked" channel="ax_transferOrderPacked_input_channel"/>
</int:payload-type-router>
<!-- ENDPOINTS -->
<!-- endpoint configurations connecting queues with channels -->
<int-jms:message-driven-channel-adapter id="articleMasterDataConsumerChannelAdapter" connection-factory="connectionFactory"
destination-name="${queue.bwh.articlemasterdata.in}" channel="bwh_articleMasterData_input_channel"
message-converter="messageConverter" acknowledge="client" max-concurrent-consumers="10"
auto-startup="false"/>
<int-jms:message-driven-channel-adapter id="transferOrderConsumerChannelAdapter" connection-factory="connectionFactory"
destination-name="${queue.bwh.transferorder.in}" channel="bwh_transferOrder_input_channel"
message-converter="messageConverter" acknowledge="client" max-concurrent-consumers="5"
auto-startup="false"/>
<int-jms:outbound-channel-adapter id="transferOrderPackedProducerChannelAdapter" connection-factory="connectionFactory"
destination-name="${queue.ax.transferorderpacked.in}" channel="ax_transferOrderPacked_input_channel"
message-converter="messageConverter" delivery-persistent="true" session-transacted="true"
auto-startup="false"/>
<!-- add your endpoint here... -->
<!-- REMEMBER: If auto-startup is set to false (which is recommended for all channel adapters) -->
<!-- the channel adapter has to be registered in ecomxConsumerChannelAdapterContainer below!!! -->
<!-- gateway definitions usually injected by producer-services and used to send messages to an outbound-channel-adapter -->
<int:gateway default-request-channel="output_enricher_channel" service-interface="de.lo.bwh.jms.gateway.EcomxProducerGateway"/>
<!-- connect endpoints with services -->
<int:service-activator input-channel="bwh_articleMasterData_input_channel" ref="ecomxArticleMasterDataConsumer"/>
<int:service-activator input-channel="bwh_transferOrder_input_channel" ref="ecomxTransferOrderConsumer"/>
<!-- container for endpoints used for start / stop all registered consumers / producers at once -->
<bean id="ecomxConsumerChannelAdapterContainer" class="de.lo.bwh.jms.EcomxConsumerChannelAdapterContainer">
<property name="endpoints">
<list value-type="org.springframework.integration.jms.JmsMessageDrivenEndpoint">
<ref bean="articleMasterDataConsumerChannelAdapter"/>
<ref bean="transferOrderConsumerChannelAdapter"/>
</list>
</property>
</bean>
<bean id="ecomxProducerChannelAdapterContainer" class="de.lo.bwh.jms.EcomxProducerChannelAdapterContainer">
<property name="endpoints">
<list value-type="org.springframework.integration.endpoint.PollingConsumer">
<ref bean="transferOrderPackedProducerChannelAdapter"/>
</list>
</property>
</bean>
</beans>
<Resource name="jms/connectionFactory"
auth="Container"
type="org.apache.activemq.ActiveMQConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://my.url.net:61616"
brokerName="myActiveMQBroker"/>
嗯,这不适用于回滚消息,因为
usingIdCache=“true”
。消息会返回到数据库,但它们不会被下一次轮询拾取,因为它们的ID在内存idCache
中
我们提供此建议以处理已处理或回滚的消息:
<int:transaction-synchronization-factory id="syncFactory">
<int:after-commit expression="@store.removeFromIdCache(headers.id.toString())" />
<int:after-rollback expression="@store.removeFromIdCache(headers.id.toString())"/>
</int:transaction-synchronization-factory>
...
<int:poller id="defaultPoller" default="true" fixed-delay="500">
<int:transactional propagation="REQUIRED" isolation="DEFAULT"
synchronization-factory="syncFactory"
transaction-manager="transactionManager"/>
</int:poller>
...
独立于TX,结果消息id将从idCache
中删除。在你的情况下,它将准备再进行一次投票
请参阅中的更多信息。而JdbcChannelMessageStore#setUsingIdCache
上的JavaDocs也显示了同样的情况
<int:transaction-synchronization-factory id="syncFactory">
<int:after-commit expression="@store.removeFromIdCache(headers.id.toString())" />
<int:after-rollback expression="@store.removeFromIdCache(headers.id.toString())"/>
</int:transaction-synchronization-factory>
...
<int:poller id="defaultPoller" default="true" fixed-delay="500">
<int:transactional propagation="REQUIRED" isolation="DEFAULT"
synchronization-factory="syncFactory"
transaction-manager="transactionManager"/>
</int:poller>