关于rabbitmq的自己的一点小总结
- 1.路由问题exchange(简单介绍常用的三种路由direct,topic,fanout)
- 2.死信问题
spring -pom配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>rabbitmq-spring</groupId>
<artifactId>rabbitmq-spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<rabbitmq.version>3.0.4</rabbitmq.version>
<spring.amqp.version>1.3.9.RELEASE</spring.amqp.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.1.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>${rabbitmq.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>${spring.amqp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp</artifactId>
<version>${spring.amqp.version}</version>
<classifier>sources</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.10</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.10</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.9</version>
</dependency>
</dependencies>
</project>
###spring-rabbit.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:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd">
<!-- 创建connectionFactory -->
<bean id="rabbitConnectionFactory"
class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<constructor-arg value="127.0.0.1"/>
<property name="username" value="admin"/>
<property name="password" value="password"/>
<property name="virtualHost" value="/"/>
<!-- 下面根据需求定义-->
<property name="connectionTimeout" value="10000"/>
<property name="channelCacheSize" value="5"/>
</bean>
<!-- 创建rabbitAdmin 代理类 -->
<bean id="rabbitAdmin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="rabbitConnectionFactory" />
<!-- chanel缓存数量 -->
<property name="channelCacheSize" value="25" />
</bean>
<!-- 创建rabbitTemplate 消息模板类 若不绑定exchang,routingKey则发布消息时需要手动传入exchang,routingKey -->
<bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate" >
<constructor-arg ref="rabbitConnectionFactory"/>
<!--
<property name="exchange" value="directExchangeTest" />
<property name="routingKey" value="directRoutingKey"/>
-->
</bean>
<!-- 声明Queue并设定Queue的名称 durable是否持久化 auto-delete自动删除,没有任何消费者订阅就自动删除 exclusive排他 -->
<rabbit:queue name="task_queue" durable="true" auto-delete="false" exclusive="false" declared-by="rabbitAdmin" />
<rabbit:queue name="hello" durable="true" auto-delete="false" exclusive="false" declared-by="rabbitAdmin" >
<rabbit:queue-arguments >
<!-- 死信路由器 -->
<entry key="x-dead-letter-exchange" value="dead-letter-exchange" />
<!-- 死信路由routingKey-->
<entry key="x-dead-letter-routing-key" value="hello" />
<!-- 消息TTL过期 做延迟消费-->
<entry key="x-message-ttl">
<value type="java.lang.Long">50000</value>
</entry>
<!--队列达到最大长度 ,超过最大长度就会丢失 -->
<entry key="x-max-length">
<value type="java.lang.Long">100</value>
</entry>
</rabbit:queue-arguments>
<rabbit:queue name="alter_message" durable="true" auto-delete="false" exclusive="false" declared-by="rabbitAdmin" />
<rabbit:queue name="dead" durable="true" auto-delete="false" exclusive="false" declared-by="rabbitAdmin" />
<!-- 声明业务路由-->
<rabbit:topic-exchange name="testEx" durable="true" auto-delete="false" declared-by="rabbitAdmin" >
<rabbit:exchange-arguments >
<!-- alternate-exchange属性所有与业务路由不匹配的消息路由到名为alter的AE路由 -->
<entry key="alternate-exchange" value="alter" />
</rabbit:exchange-arguments>
<rabbit:bindings>
<!--绑定routingKey,queue -->
<rabbit:binding queue="hello" pattern="hello"></rabbit:binding>
<rabbit:binding queue="task_queue" pattern="task_queue"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
<!-- 定义死信路由-->
<rabbit:topic-exchange name="dead-letter-exchange" durable="true" auto-delete="false" declared-by="rabbitAdmin" >
<rabbit:bindings>
<!-- queue的 routingKey 为路由到死信路由的queue中的 x-dead-letter-routing-key属性的值本例中为路由message到死信的queue为hello-->
<rabbit:binding queue="dead" pattern="hello"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
<!-- 定义警告队列-->
<rabbit:fanout-exchange name="alter">
<rabbit:exchange-arguments >
<!-- 是否是内部路由 true客户端不能发布消息到此交换机,只能通过其他交换机一起使用 -->
<entry key="internal" value="true" />
</rabbit:exchange-arguments>
<rabbit:bindings>
<rabbit:binding queue="alter_message"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<!-- 定义监听器工厂-->
<bean id="rabbitListenerContainerFactory" class="org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory">
<property name="connectionFactory" ref="rabbitConnectionFactory" />
<property name="transactionManager" ref="transactionManager" />
<property name="concurrentConsumers" value="1" />
<property name="maxConcurrentConsumers" value="10" />
<!-- 其他视需求添加-->
<!--
<property name="messageConverter" ref="jsonMessageConverter" />
<property name="taskExecutor" ref="taskExecutor" />
<property name="channelTransacted" value="true" />
<property name="adviceChain">
<array>
<ref bean="retryInterceptor" />
</array>
</property>
-->
</bean>
<!-- 定义监听器容器-->
<!-- acknowledge应答方式默认为true自动应答,这里选择手动应答 prefetch 一次取queue中message数量-->
<rabbit:listener-container connection-factory="rabbitConnectionFactory" acknowledge="manual" prefetch="1">
<rabbit:listener queues="directQueue1" ref="directQueueMessageListener" />
<rabbit:listener queues="topicQueue" ref="topicQueueMessageListener" />
<rabbit:listener queues="fanoutQueue1" ref="fanoutQueueMessageListener"/>
<rabbit:listener queues="hello" ref="topicQueueMessageListener" />
</rabbit:listener-container>
生产者发布消息
package rabbitmq.producer.biz.impl;
import java.io.IOException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import rabbitmq.producer.biz.MessageProducerBiz;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ReturnListener;
/**
* 文件名:MessageProducer.java
* 描述:
* 作者:gustar
* 日期:2017年6月27日下午2:37:41
*/
@Service("messageProducerBiz")
public class MessageProducerBizImpl implements MessageProducerBiz {
@Autowired
private AmqpTemplate rabbitTemplate;
@Autowired
private CachingConnectionFactory rabbitConnectionFactory;
/**
* 发布 message
* rabbitTemplate绑定exchange,routingKey属性值
* @param message
*/
public void mqRoute(Object message) {
/*如果rabbitTemplate未绑定exchange和routingKey采用此发送发送回丢失消息应采用下面方式*/
rabbitTemplate.convertAndSend(message);
}
/**
* 发布 message
* @param exchange 路由器
* @param routingKey 路由规则
* @param message
* 作者:gustar
* 日期:2017年6月29日上午11:33:10
*/
public void mqRoute(String exchange, String routingKey, Object message) {
rabbitTemplate.convertAndSend(exchange, routingKey, message);
}
/**
* 基于RPC(远程调用等待消息回复)
* @param exchange 路由器
* @param routingKey 路由规则
* @param message
* 作者:gustar
* 日期:2017年6月28日上午10:47:28
*/
public Object sendAndReceive(String exchange, String routingKey, Object message) {
return rabbitTemplate.convertSendAndReceive(message);
}
}
消费者消费消息
package rabbitmq.consumer.queue.listener;
import java.io.IOException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;
import rabbitmq.util.GlobalVar;
import com.rabbitmq.client.Channel;
/**
* 文件名:TopicMessageListener.java
* 描述:
* 作者:gustar
* 日期:2017年6月27日下午2:27:14
*/
@Component("topicQueueMessageListener")
public class TopicQueueMessageListener implements ChannelAwareMessageListener {
public void onMessage(Message message, Channel channel) throws IOException {
// Object obj = null;
String messageHandleStatus = "MESSAGE_HANDLE_ACCEPT";
try {
// obj = msgConverter.fromMessage(message);
System.out.println("TopicQueueMessageListener onMessage method do topic--" + message);
} catch (Exception e) {
// 根据异常种类决定是ACCEPT、RETRY还是 REJECT
} finally {
if ("MESSAGE_HANDLE_ACCEPT".equals(messageHandleStatus)) {
// 确认消息,false只确认当前一个消息收到,true确认所有consumer获得的消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} else if ("MESSAGE_HANDLE_RETRY".equals(messageHandleStatus)) {
// ack返回false,并重新回到队列 第一个boolean参数:是否批量 ,第二个参数:被拒绝的是否重新入队列
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
} else {
/** 拒绝消息 ,回死信队列 */
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
}
}
}
}