最近由于刚练手消息中间件,就拿了一个activeMQ试试,在练习的过程中遇到了比较明显的问题:就是主题模型下的消息队列,持久化订阅者的实现。具体表象就是,我的接收者重启后接收不到发送者已发送而未消费的消息,非得接收者先启动好,然后发送者推送消息,才可以接收到。这不是我想要的,实际是要求接收者重启后能主动拉取发送者已发送而未消费的消息。另外进入Messages Dequeued的消息无法再次消费。
实现订阅者持久化,前提有:发送者消息持久化、开启发布/订阅者模式、进行持久化模式,接收者 工厂(CachingConnectionFactory或SingleConnectionFactory)指定接收者id属性值clientId,消息队列容器开启发布/订阅者模式、消息持久化设置、接收者id。
分享配置如下:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"
default-lazy-init="false">
<!-- 连接工厂 -->
<bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${active.mq.url}"></property>
<property name="userName" value="${active.mq.username}"></property>
<property name="password" value="${active.mq.password}"></property>
<property name="useAsyncSend" value="true"></property>
</bean>
</property>
<property name="maxConnections" value="100"></property>
</bean>
<!-- 发送者相关配置 开始 -->
<!-- 连接工厂 -->
<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsFactory"/>
<property name="sessionCacheSize" value="100"/>
</bean>
<!-- jms消息队列模板 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachingConnectionFactory"/>
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
</property>
<!-- 开启订阅模式 必需-->
<property name="pubSubDomain" value="true" />
<!-- 进行持久化 必需 -->
<property name="deliveryMode" value="2" />
<!-- 消息持久化 必需 -->
<property name="explicitQosEnabled" value="true" />
</bean>
<!-- 发送者相关配置 结束 -->
<!-- 接收者相关配置 开始 -->
<!--使用缓存可以提升效率,配置多个持久化订阅者 -->
<bean id="cachingConnectionFactory1" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsFactory"/>
<property name="clientId" value="${active.mq.topic1}" />
<property name="sessionCacheSize" value="100"/>
</bean>
<bean id="cachingConnectionFactory2" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsFactory"/>
<property name="clientId" value="${active.mq.topic2}" />
<property name="sessionCacheSize" value="100"/>
</bean>
<!--消息接收目的地1-->
<bean id="destination1" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="${active.mq.topic1}"/>
</bean>
<!--消息接收目的地2-->
<bean id="destination2" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="${active.mq.topic2}"/>
</bean>
<!--消息队列容器1-->
<bean id="jmsContainer1" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="cachingConnectionFactory1"/>
<property name="destination" ref="destination1"/>
<property name="messageListener" ref="messageListener"/>
<!-- 消息确认机制 自动 -->
<property name="sessionAcknowledgeMode" value="1"/>
<!-- 发布订阅模式 必需 -->
<property name="pubSubDomain" value="true" />
<!-- 消息持久化值设置为true 必需-->
<property name="subscriptionDurable" value="true" />
<!--消息接收超时 -->
<property name="receiveTimeout" value="10000" />
<!-- 接收者ID 必需-->
<property name="clientId" value="${active.mq.topic1}" />
<!-- 持久订阅者名称 必需-->
<property name="durableSubscriptionName" value="${active.mq.topic1}" />
</bean>
<!--消息队列容器2-->
<bean id="jmsContainer2" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="cachingConnectionFactory2"/>
<property name="destination" ref="destination2"/>
<property name="messageListener" ref="messageListener"/>
<!-- 消息确认机制 自动 -->
<property name="sessionAcknowledgeMode" value="1"/>
<!-- 发布订阅模式 必需-->
<property name="pubSubDomain" value="true" />
<!-- 消息持久化值设置为true 必需-->
<property name="subscriptionDurable" value="true" />
<!--消息接收超时 -->
<property name="receiveTimeout" value="10000" />
<!-- 接收者ID 必需-->
<property name="clientId" value="${active.mq.topic2}" />
<!-- 持久订阅者名称 必需-->
<property name="durableSubscriptionName" value="${active.mq.topic2}" />
</bean>
<!--消息接收监听器-->
<bean id="messageListener" class="com.xxx.xxx.xxx.xxx.myMessageListener">
</bean>
<!-- 接收者相关配置 结束 -->
</beans>
特别注意一下clientId属性的设置,另外在测试的时候最好将发送者和接收者分开启动,这样更容易测试持久订阅。最后感谢已经将相关文档提供在论坛上供我参考过的大佬们~