springboot整合activemq queue topic消息类型 及消息的手动签收、持久化 — 3
前言
现在我们已经实现了一个基本可以解决所有业务需求的消息队列。但是目前还有一些需要完善的工作,比如消息的重发机制,对“死信”的管理和处理等
消息重发
消息的重发规则是可以配置的,我们在consumer中配置如下bean
@Bean
public RedeliveryPolicy redeliveryPolicy() {
RedeliveryPolicy redeliveryPolicy= new RedeliveryPolicy();
// 是否在每次尝试重新发送失败后,增长这个等待时间
redeliveryPolicy.setUseExponentialBackOff(true);
// 重发次数
redeliveryPolicy.setMaximumRedeliveries(5);
// 重发时间间隔,默认为1000ms
redeliveryPolicy.setInitialRedeliveryDelay(1000);
// 重发时长递增
redeliveryPolicy.setBackOffMultiplier(2);
// 是否避免消息碰撞
redeliveryPolicy.setUseCollisionAvoidance(false);
// 设置重发最大拖延时间
redeliveryPolicy.setMaximumRedeliveryDelay(-1);
return redeliveryPolicy;
}
在listener中加入该策略(示例jmsListenerContainerQueue)
/**
* Queue模式的DefaultJmsListenerContainerFactory
* @param activeMQConnectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ActiveMQConnectionFactory activeMQConnectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
// 手动签收
bean.setSessionTransacted(false);
bean.setSessionAcknowledgeMode(INDIVIDUAL_ACKNOWLEDGE);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy());
bean.setConnectionFactory(activeMQConnectionFactory);
return bean;
}
修改签收逻辑(不手动签收,直接使用session.recover()
触发消息重发)
@Override
@JmsListener(destination = "default", containerFactory = "jmsListenerContainerQueue")
public void reciveQueueText(ActiveMQMessage message, Session session) {
int i = 0;
try {
System.out.println("收到消息" + message +":"+ i++);
// message.acknowledge();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
try {
session.recover();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
测试
- 启动provider
- 启动consumer
- 发送一条queue消息
- 我们发现消息被发送了6次(重发5次)后被消费,并进入了一个名为ActiveMQ.DLQ的队列
这便是我们提到的“死信”,即超过重发规则限制的消息会统一进入该队列管理。但是所有“死信”都在这里,因此不便于我们对一些“特殊”的“死信”进行单独管理。
“死信”管理
“死信”管理策略
修改activemq.xml,配置如下策略
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" persistent="true" dataDirectory="${activemq.data}">
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" >
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true" />
</deadLetterStrategy>
</policyEntry>
<policyEntry topic=">" >
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true" />
</deadLetterStrategy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
...
</broker>
测试
- 重启activemq
- 启动provider
- 启动consumer
- 发送一条queue消息
- 可以发现,在该策略下,死信进入可辨识的DLQ.default队列,即DLQ+destination,这样我们就可以针对单独的“死信”队列去处理这些“死信”啦!
- 其他策略不常用,需要的可自行学习
“死信”处理
@Override
@JmsListener(destination = "DLQ.default", containerFactory = "jmsListenerContainerQueue")
public void reciveDLQDefault(ActiveMQMessage message, Session session) {
System.out.println("处理死信" + message);
try {
message.acknowledge();
} catch (JMSException e) {
e.printStackTrace();
}
}
测试
直接重启consumer,发现之前的两条死信都被成功处理
topic模式消息重发
最后,我们再来测试一下topic模式下的消息重发和“死信”处理
以同样的方法测试后,我们发现topic的“死信”会被收到ActiveMQ.DLQ.topic+destination下,不过无所谓,想要处理的话,方法也如出一辙,不再赘述了。
总结
到目前为止,对activemq的集成算是暂告一段落了。我们完成了
- 点对点的消息实时收发
- 点对点的消息持久化
- 点对点消息手动签收
- 点对点消息重发
- 点对点“死信”处理
- 主题\订阅模式消息实时收发
- 主题\订阅模式消息持久化
- 主题\订阅模式消息手动签收
- 主题\订阅模式消息重发
- 主题\订阅模式“死信”处理
处理各种棘手的业务需求怕是没有问题了8!!
资料
源码地址
https://github.com/dangzhicairang/my-cloud.git
配置中心地址
https://github.com/dangzhicairang/my-config.git