RabbitMQ
延时队列:
1. 需要rabbitmq在1.6及以上的版本,spring在4.2以上。本项目使用的版本为spring4.2.7,rabbitmq1.6.3,若之前有低版本则需要升级(1.6以上的版本中才有delayed属性,此属性为设置延时必须属性)
Pom文件(spring相关截图省略)
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.6.3.RELEASE</version>
</dependency>
2. 在maven引入jar包后,还需在rabbitmq-xml中更改此处后才会有delayed属性。
3.此处为rabbitmq-xml中”生产者”,”路由器”的配置
connection-factory:创建rabbitmq连接
Queue:队列 < durable 持久化 auto-delete 自动删除 exclusive 排他性,只对首次声明他的连接可见>
direct-exchange:路由器 < delayed="true" 是否支持延时> 路由器中的queue和key用于根据生产者中的发送的参数key,决定发送至对应的queue中。
template:模板 exchange对应路由器
<beanid="testMqProvider"><bean/>: 生产者 ref对应模板
<!--test延时队列-->
<!-- 连接服务配置 --> <!--suppress UnparsedCustomBeanInspection --> <rabbit:connection-factory id="connectionFactory" host="${mq.addresses.url}" username="${mq.username}"password="${mq.password}" channel-cache-size="50" port="${mq.port}" />
<!--转换为fastjson方法,继承并重写方法--> <bean id="jsonMessageConverter" class="com.keel.common.mq.FastJsonMessageConverter"></bean>
<rabbit:queue id="${rabbit_queue_test}" durable="true" auto-delete="false" exclusive="false" name="${rabbit_queue_test}" declared-by="connectAdmin"/> <rabbit:direct-exchange name="${rabbit_exchange_test}" durable="true" auto-delete="false" id="${rabbit_exchange_test}" delayed="true" declared-by="connectAdmin"> <rabbit:bindings> <rabbit:binding queue="${rabbit_queue_test}"key="${rabbit_queue_routkey_test_statistics}"/> </rabbit:bindings> </rabbit:direct-exchange> <rabbit:template id="testTemplate" connection-factory="connectionFactory" exchange="${rabbit_exchange_test}" message-converter="jsonMessageConverter"/> <bean id="testMqProvider" class="com.duojia.eagle.manager.message.TestMqProvider" > <property name="amqpTemplate" ref="testTemplate" /> </bean>
3. 此处为生产者,之所以发送两条不同是延时消息,是为了验证:到期的消息接收,不会受队列中位置的影响。
例如:第一个消息三十秒过期,第二个消息十秒过期,消费者接受会先接收到十秒的消息,后接受到三十秒的消息。此时队列中会对延时时间排列消息出队列的顺序。
4. public class TestMqProvider { private static Logger log = LoggerFactory.getLogger(TestMqProvider.class); @Autowired private RabbitTemplate amqpTemplate; public void setAmqpTemplate(RabbitTemplate amqpTemplate) { this.amqpTemplate = amqpTemplate; } private String rabbit_queue_routkey_test_statistics = "testroutOpttest1"; public void testuser() throws InterruptedException { sendDataToQueue(rabbit_queue_routkey_test_statistics,111); sendDataToQueue2(rabbit_queue_routkey_test_statistics,222); } public void sendDataToQueue(String queueKey, Object object) { log.info("生产者 ==============================================="+object); log.info("生产者 ==============================================="+String.valueOf(System.currentTimeMillis())); try { amqpTemplate.convertAndSend(queueKey,object,new MessagePostProcessor(){ @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().setDelay(30000); return message; } }); }catch (Exception e){ e.printStackTrace(); } } public void sendDataToQueue2(String queueKey, Object object) { log.info("生产者 ==============================================="+object); log.info("生产者 ==============================================="+String.valueOf(System.currentTimeMillis())); try { amqpTemplate.convertAndSend(queueKey,object,new MessagePostProcessor(){ @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().setDelay(10000); return message; } }); }catch (Exception e){ e.printStackTrace(); } } }
4.此处为rabbit-xml中”消费者” “监听”的配置
<bean id="testMqConstumer" class="com.duojia.eagle.manager.message.TestMqConstumer"></bean>
<rabbit:listener-container connection-factory="connectionFactory" concurrency="2" channel-transacted="false" acknowledge="auto"> <rabbit:listener queues="${rabbit_queue_test}" ref="testMqConstumer" method="onMessage"/> </rabbit:listener-container>
5. 此处为消费者
6. public class TestMqConstumer implements MessageListener { private static Logger log = LoggerFactory.getLogger(TestMqConstumer.class); @Override public void onMessage(Message message) { try { String orderNo = new String(message.getBody(), "utf-8"); log.info("消费者 ==============================================="+orderNo); log.info("消费者 ==============================================="+String.valueOf(System.currentTimeMillis())); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }
6.调用生产者的方法实例
public String testmq(String orderNo) throws Exception{ log.info("manager ==============================================="+orderNo); log.info("manager ==============================================="+String.valueOf(System.currentTimeMillis())); testMqProvider.testuser(orderNo); return "000"; }
7. 在修改过xml中的queue 和exchange配置后,要在服务器删除掉原先已有的queue和exchange。在删除的时候发现删除不久后,queue和exchange又自动创建出来了。后来发现,本地和测试服连接的是同一个mq,测试服一直在运行,rabbitmq会根据rabbitmq-xml的配置不断的检测并创建相应的组件(queue,exchange等),并且当同名的组件。因此当有连接rabbitmq的服务时,本地更改xml配置时无效。解决方法:重新命名或者停掉所有连接该mq的服务,更改xml配置后再发布,mq相关组件在项目启动时就已经开始并完成创建。