明确什么时候会引发消息重发机制
1.在使用事务的Session中,调用rollback()方法;
2.在使用事务的Session中,调用commit()方法之前就关闭了Session;
3.在Session中使用CLIENT_ACKNOWLEDGE签收模式或者INDIVIDUAL_ACKNOWLEDGE模式,并且调用了recover()方法。
可以通过设置ActiveMQConnectionFactory来定制想要的再次传送策略。
消息生产者关键配置
在第三方connectionFactory的bean中(在这里就是AmqConnectionFactory)加入这段配置
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${brokerURL}"/>
<property name="userName" value="admin"></property>
<property name="password" value="admin"></property>
<property name="redeliveryPolicy">
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<!--是否在每次尝试重新发送失败后,增长这个等待时间 -->
<property name="useExponentialBackOff" value="true"/>
<!--重发次数,默认为6次 这里设置为1次 -->
<property name="maximumRedeliveries" value="2"/>
<!--重发时间间隔,默认为1秒 -->
<property name="initialRedeliveryDelay" value="1000"/>
<!--第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value -->
<property name="backOffMultiplier" value="2"/>
<!--最大传送延迟,只在useExponentialBackOff为true时有效(V5.5),假设首次重连间隔为10ms,倍数为2,那么第二次重连时间间隔为 20ms,
第三次重连时间间隔为40ms,当重连时间间隔大的最大重连时间间隔时,以后每次重连时间间隔都为最大重连时间间隔。 -->
<property name="maximumRedeliveryDelay" value="1000"/>
</bean>
</property>
</bean>
消息消费者关键配置
<jms:listener-container connection-factory="connectionFactory"
destination-type="durableTopic"
acknowledge="client">
<!--clientid+subcription的值为监听器注册到broker的名字-->
<jms:listener destination="add.page.topic" ref="addPageMessageListener" subscription="add.Page"/>
<jms:listener destination="del.page.topic" ref="delPageMessageListener" subscription="del.Page"/>
</jms:listener-container>
关键配置是将应答模式设置成"client"!!!
消费者监听类关键代码
1.session.recover();调用此方法,消息才会重发
2.注意如果消费成功,一定要调用om.acknowledge();消息才会出队,防止消息堆积
public class AddPageMessageListener implements SessionAwareMessageListener<ObjectMessage> {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Reference(timeout = 10000)
private GoodsService goodsService;
@Value("${staticUrl}")
private String staticUrl;
@Override
public void onMessage(ObjectMessage om, Session session) throws JMSException {
Long[] ids = (Long[]) om.getObject();
Configuration configuration = freeMarkerConfigurer.getConfiguration();
Template template = null;
try {
//引发异常
// int i = 1/0;
template = configuration.getTemplate("item.ftl");
for (Long id : ids) {
Map<String, Object> dataModel = goodsService.getGoodsByGoodsId(id);
OutputStreamWriter outputStreamWriter =
new OutputStreamWriter(new FileOutputStream(staticUrl+id+".html"),"UTF-8");
template.process(dataModel, outputStreamWriter);
outputStreamWriter.close();
}
//必须应答,broker中的消息才会出队,相当于提交事务
om.acknowledge();
} catch (Exception e) {
//调用recover方法,引发消息重发
session.recover();
}
}
}