activemq 消息消费失败之后如何重新消费

原创 2015年11月19日 16:23:21

在不开启事物的情况下 采用的是应答模式4(ActiveMQSession.AUTO_ACKNOWLEDGE)消费一次 应答一次

这时候消费失败了,由于没有配置死亡队列,消息就不会被消费堆积在队列中,那么怎么才可以让消息再被消费呢?

由于项目中的应用场景,有个方案启动和停止的功能,项目启动启动监听,项目停止,停止监听

具体实现代码如下

public class MqService {

	private JmsTemplate jmsTemplate;

	private CachingConnectionFactory cachingProductConnectionFactory;

	private CachingConnectionFactory cachingConsumersConnectionFactory;

	private static final String ACTIVEMQQUEUE_OPTIMIZATION = "";// 性能优化参数
																// consumer.prefetchSize预加载消息
																// 20条
																// ?consumer.prefetchSize=20

	/**
	 * 发送消息
	 * 
	 * @param ryzhMessage
	 */
	public void send(final RyzhMessage ryzhMessage) {
		
		// 得到MQ工具类
		RyzhMqHolder hodler = mqHolders.get(ryzhMessage.getShcemeId());
		// 发送信息
		jmsTemplate.setConnectionFactory(cachingProductConnectionFactory);
		jmsTemplate.send(hodler.getDestination(), new MessageCreator() {
			public Message createMessage(Session session) throws JMSException {
				ObjectMessage objectMessage = session.createObjectMessage();
				objectMessage.setObject(ryzhMessage);
				return objectMessage;
			}
		});
	}

	/**
	 * 监听
	 * 
	 * @param schemeId
	 * @param receiver
	 */
	public void startListen(RyzhScheme scheme) {
		RyzhMqHolder holder = mqHolders.get(scheme.getSchemeId());
		try {
			if (holder == null) {
				RyzhConsumer consumer = (RyzhConsumer) SpringBeanUtils.getBean("ryzhConsumer");
				consumer.setScheme(scheme);
				logger.info("RyzhMqService-启动消息队列监听器 schemeId=" + scheme.getSchemeId());
				// 如果是为空
				holder = new RyzhMqHolder();
				// 得到整合方案的配置
				TRyzhFa tRyzhFa = ((RyzhConsumer) consumer).getScheme().getZhfa();
				// 得到消息队列配置的信息
				String xxdlJson = tRyzhFa.getXxdlpz();
				// json转map
				RyzhMqConfig ryzhMqConfig = JSON.parseObject(xxdlJson, RyzhMqConfig.class);
				// 设置方案ID
				holder.setSchemeId(scheme.getSchemeId());
				// 设置目的地
				ActiveMQQueue destination = new ActiveMQQueue(RyzhMqConfig.QUEUE_NAME + scheme.getSchemeId() + ACTIVEMQQUEUE_OPTIMIZATION);
				holder.setDestination(destination);
				// 创建监听器
				DefaultMessageListener listener = new DefaultMessageListener();
				// 给监听器设置消费者
				listener.setReceiver(consumer);
				// 将监听器保存在holder中
				holder.setListener(listener);
				// 创建监听容器
				DefaultMessageListenerContainer listenerContainer = new DefaultMessageListenerContainer();
				// 监听容器属性的配置
				listenerContainer.setConnectionFactory(cachingConsumersConnectionFactory);
				// 设置目的地
				listenerContainer.setDestination(destination);
				// 设置监听器
				listenerContainer.setMessageListener(listener);
				// 设置消费者集群数
				listenerContainer.setConcurrentConsumers(ryzhMqConfig.getConcurrentConsumers());
				// 设置监听队列还是主题 默认是队列
				listenerContainer.setPubSubDomain(RyzhMqConfig.PUBSUB_DOMAIN);
				listenerContainer.setPubSubNoLocal(false);
				// listenerContainer.setAcceptMessagesWhileStopping(true);
				// 设置应答模式 默认是4
				listenerContainer.setSessionAcknowledgeMode(RyzhMqConfig.SESSION_ACKNOWLEDGEMODE);
				// 设置是否启动事物 默认不开启
				listenerContainer.setSessionTransacted(RyzhMqConfig.SESSION_TRANSACTED);
				// 将监听容器保存在holder中
				holder.setListenerContainer(listenerContainer);
				// 将holder缓存在map中
				mqHolders.put(scheme.getSchemeId(), holder);
				// 初始化容器
				holder.getListenerContainer().initialize();
				// 启动监听
				holder.getListenerContainer().start();
				logger.info("RyzhMqService-消息队列监听器启动成功 schemeId=" + scheme.getSchemeId());
			}
		} catch (Exception e) {
			logger.error("RyzhMqService-消息队列监听器启动失败 schemeId=" + scheme.getSchemeId(), e);
		}
	}

	public void stopListen(RyzhScheme scheme) {
		RyzhMqHolder ryzhMqHolder = mqHolders.get(scheme.getSchemeId());
		// 停止监听
		ryzhMqHolder.getListenerContainer().destroy();
		// 移除缓存
		mqHolders.remove(scheme.getSchemeId());
	}

	/**
	 * 取得MQHolder
	 * 
	 * @param ryzhMessage
	 * @return
	 */

	public Map<String, RyzhMqHolder> getMqHolders() {
		return mqHolders;
	}

	public void setMqHolders(Map<String, RyzhMqHolder> mqHolders) {
		this.mqHolders = mqHolders;
	}

	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	public CachingConnectionFactory getCachingProductConnectionFactory() {
		return cachingProductConnectionFactory;
	}

	public void setCachingProductConnectionFactory(CachingConnectionFactory cachingProductConnectionFactory) {
		this.cachingProductConnectionFactory = cachingProductConnectionFactory;
	}

	public CachingConnectionFactory getCachingConsumersConnectionFactory() {
		return cachingConsumersConnectionFactory;
	}

	public void setCachingConsumersConnectionFactory(CachingConnectionFactory cachingConsumersConnectionFactory) {
		this.cachingConsumersConnectionFactory = cachingConsumersConnectionFactory;
	}

}

具体的xml配置如下


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:lang="http://www.springframework.org/schema/lang"
	xsi:schemaLocation="
	   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
	default-autowire="byName">

	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="cachingProductConnectionFactory"></property>
		<!-- 持久化 -->
		<property name="deliveryMode" value="2"></property>
		<!-- 不开启事物 -->
		<property name="sessionTransacted" value="false"></property>
		<!-- 应答模式是 INDIVIDUAL_ACKNOWLEDGE -->
		<property name="sessionAcknowledgeMode" value="4"></property>
	</bean>

	<bean id="ryzhMqService" class="com.dragonsoft.rygl.mq.RyzhMqService"
		scope="singleton">
		<property name="cachingConsumersConnectionFactory" ref="cachingConsumersConnectionFactory"></property>
		<property name="cachingProductConnectionFactory" ref="cachingProductConnectionFactory"></property>
		<property name="jmsTemplate" ref="jmsTemplate" />
	</bean>

	<bean id="defaultRyzhProduceProcessor"
		class="com.dragonsoft.rygl.ryzh.service.produce.DefaultRyzhProduceProcessor"
		scope="prototype">
		<property name="mgService" ref="ryzhMqService"></property>
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
		<property name="ip" value="${jmx.ip}"></property>
		<property name="port" value="${jmx.port}"></property>
		<property name="dataSourceManager" ref="dataSourceManager"></property>
	</bean>
	<!-- 生产者专用缓存池 -->
	<bean id="cachingProductConnectionFactory"
		class="org.springframework.jms.connection.CachingConnectionFactory">
		<property name="targetConnectionFactory" ref="connectionFactory"></property>
		<property name="reconnectOnException" value="true"></property>
		<property name="sessionCacheSize" value="${jms.sessionCacheSize}"></property>
	</bean>
	<!-- 消费者专用缓存池 -->
	<bean id="cachingConsumersConnectionFactory"
		class="org.springframework.jms.connection.CachingConnectionFactory">
		<property name="targetConnectionFactory" ref="connectionFactory"></property>
		<property name="reconnectOnException" value="true"></property>
		<property name="sessionCacheSize" value="${jms.sessionCacheSize}"></property>
		<span style="color:#ff0000;"><property name="cacheConsumers" value="false"></property>
		<property name="cacheProducers" value="false"></property></span>
	</bean>
	<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
		<property name="brokerURL" value="${jms.brokerURL}" />
		<property name="userName" value="${jms.userName}"></property>
		<property name="password" value="${jms.password}"></property>
		<property name="useAsyncSend" value="${jms.useAsyncSend}"></property>
<span style="white-space:pre">		</span><!--
		<property name="redeliveryPolicy" >
			<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
				<property name="useExponentialBackOff" value="true"/>
				<property name="maximumRedeliveries" value="5"/><!-- 重发次数 5次 -->
				<property name="initialRedeliveryDelay" value="100"/><!-- 重发间隔时间100毫秒 -->
				<property name="backOffMultiplier" value="2.0"/>
			</bean>
		</property><pre name="code" class="html"><span style="white-space:pre">		</span>-->
</bean></beans>


注意红色部分,需要缓存,否则监听会被缓存无法stop。

以下就可以达到不用配置死信队列就可以重新消费信息。(其实原理就是重启了监听容器)


版权声明:本文为博主原创文章,未经博主允许不得转载。

ActiveMQ中消费者是如何接收消息的(二)

上篇文章大致讲述了同步消费者和异步消费者接收消息的异同(详见《ActiveMQ中消费者是如何接收消息的(一)》http://manzhizhen.iteye.com/blog/2094130 ),但我...

[异步][jms][activeMq]如何做到重试机制不会导致一条消息被多次执行.

Message Queue ActiveMQ: redeliver,如何做到重试机制不会导致一条消息被多次执行.        http://stackoverflow.com/questions/4...
  • fei33423
  • fei33423
  • 2014年06月20日 18:24
  • 18016

Activemq消息确认机制

ActiveMQ消息传送机制以及ACK机制详解     AcitveMQ是作为一种消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,...
  • czp11210
  • czp11210
  • 2015年07月23日 15:06
  • 34293

ActiveMQ学习小结

ActiveMQ简介    Activemq是众多开源消息中间件的一种,支持集群,同等网络,自动检测,TCP,SSL,广播,持久化,和J2EE1.4容器无缝结合。它是apache基金会的一个项目,而且...
  • czp11210
  • czp11210
  • 2013年04月19日 08:39
  • 10691

ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message Delivery)

有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。 类似这种需求,ActiveMQ提供了一种broker...
  • KimmKing
  • KimmKing
  • 2012年12月27日 15:37
  • 22452

activemq消息确认机制

当spring与activemq集成时,如下配置确认机制 单独使用时,Session session = con...

ActiveMQ:设置多个并行的消费者

消息队列本来就是一种经典的生产者与消费者模式。生产者向消息队列中发送消息,消费者从消息队列中获取消息来消费。...

ActiveMQ的消息重试机制

消息重发机制: 1. 处理失败 指的是MessageListener的onMessage方法里抛出RuntimeException。 2. Message头里有两个相关字段:Redelivered默认...
  • KimmKing
  • KimmKing
  • 2014年02月12日 18:42
  • 15426

Activemq 常见的一些问题 心得

1.先讲严重的:服务挂掉。 这得从ActiveMQ的储存机制说起。在通常的情况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,它们的最大限制在配置文件的节点中配置。但是,在非持久化...

Spring ActiveMQ 整合(二): 重发机制(消息发送失败后的重新发送)

假如现在我手里有一个很重要的消息的,想要发给一个人,但是很不幸,消息发送失败了。这时候怎么办呢怎么解决这种尴尬的情况,这时候我们可以利用activeMQ的 消息重发机制(RedeliveryPoli...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:activemq 消息消费失败之后如何重新消费
举报原因:
原因补充:

(最多只允许输入30个字)