RabbitMQ注解方式配置说明
1.共通配置
- spring-rabbit使用1.6版本,需要spring 4.2以上才可以支持使用注解方式配置
- 每个项目配置自己的exchange,格式为项目名称简写+exchange,如:
rabbitmq.direct.exchange=ccs.direct.exchange
可以防止队列重名 - routeKey和queue的名称也要加上项目名称简写防止重名
- 例子中传输数据使用了String,实际使用时可以放入任意对象和返回。
- 附件中spring-rabbit.xml为异步回调方式的完整生产者配置
- 生产者配置时,exchange共有三种方式发送消息,含义请参考http://www.360doc.com/content/14/0608/22/834950_384932402.shtml
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
<rabbit:connection-factory id="connectionFactory"
addresses="${rabbitmq.addresses}" username="${rabbitmq.username}"
password="${rabbitmq.password}" channel-cache-size="${rabbitmq.channel.cache.size}"
<rabbit:admin connection-factory="connectionFactory"
<!-- json转换器,消息可以自动根据转换器转换格式,不配置时默认为java序列化,可以自行配置 -->
<bean id="messageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"
#地址,两个rabbitmq服务器之间为镜像队列
rabbitmq.addresses=192.168.5.130:5672,192.168.5.132:5672
rabbitmq.username=test
rabbitmq.password=test
rabbitmq.concurrentConsumers=5
rabbitmq.channel.cache.size=50
#exchange名称
rabbitmq.direct.exchange=ccs.direct.exchange
rabbitmq.fanout.exchange=ccs.fanout.exchange
rabbitmq.topic.exchange=ccs.topic.exchange
2.direct模式配置
2.1.队列配置
队列配置需要在生产者消费者两边同时配置。
如果只在生产者方配置,rabbitmq服务器中无队列时,会导致消费者服务器启动时找不到监听队列报错
<!-- 将queue和routingKey进行绑定 -->
<rabbit:queue name="ccs.queue.sync"
<rabbit:queue name="ccs.queue.async"
<!-- 定义回复queue -->
<rabbit:queue name="ccs.queue.async.reply"
<!-- direct方式:根据routingKey将消息发送到所有绑定的queue中 -->
<rabbit:direct-exchange name="${rabbitmq.direct.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.sync" key="ccs.binding.sync"
<rabbit:binding queue="ccs.queue.async" key="ccs.binding.async"
<rabbit:binding queue="ccs.queue.async.reply" key="ccs.binding.async.reply"
</rabbit:bindings>
</rabbit:direct-exchange>
注:队列分为同步和异步模式,异步模式支持异步回复功能。ccs.queue.sync队列为同步,ccs.queue.async和ccs.queue.async.reply组合为异步。
2.2.生产者配置
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="500"
<property name="multiplier" value="10.0"
<property name="maxInterval" value="10000"
</bean>
</property>
</bean>
<rabbit:template id="template" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.direct.exchange}"
<!-- exchange为direct模式 -->
<rabbit:template id="template" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.direct.exchange}"
retryTemplate为连接失败时的重发队列所用的templete
2.3.消费者配置
<rabbit:annotation-driven
<bean id="rabbitListenerContainerFactory"
class="org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory">
<property name="messageConverter" ref="messageConverter"
<property name="connectionFactory" ref="connectionFactory"
<property name="concurrentConsumers" value="3"
<property name="maxConcurrentConsumers" value="10"
</bean>
2.4.消费者配置
因为测试用的系统使用了quartz来定时发送队列,代码仅提供rabbitmq相关的功能。使用者根据需要自行修改。
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("template");
template.convertAndSend(template.getExchange(), "ccs.binding.async", id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
- ccs.binding.async为队列的bind名称,一个binding可以绑定多个队列,实现广播功能;
- 同步和异步发送部分代码相同
- MessagePostProcessor可以为队列配置一些参数,本例中配置了jobName
- SpringContextHolder为持有spring上下文的静态对象,参考如下方式配置:
SpringContextHolder配置
2.5.消费者代码示例
@Component
public class AsyncQueueListener
/**
* 同步队列
* @param id 任务ID
* @param
@RabbitListener(queues = "ccs.queue.sync")
public void hello(String id, @Header("jobName") String jobName) {
System.out.println("Received request for id " + id);
System.out.println("Received request for job name " + jobName);
}
/**
* 异步队列,SendTo为回复的队列名称
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.async")
@SendTo("ccs.queue.async.reply")
public BaseResponse hello(String id, @Header("jobName") String jobName) {
System.out.println("Received request for id " + id);
System.out.println("Received request for job name " + jobName);
//返回执行结果(成功,失败)和ID
BaseResponse response = new BaseResponse(true, id);
return
以下代码需要放在生产者服务器,监听异步消息返回的队列
@Component
public class AsyncReplyQueueLitener
private Logger logger = LoggerFactory.getLogger(AsyncReplyQueueLitener.class);
@Autowired
private CcsQtrtzLogService ccsQtrtzLogService;
//参数中使用@Header获取mesage
@RabbitListener(queues = { "ccs.queue.async.reply", "ccs.queue.bds.reply", "ccs.queue.etl.reply", "ccs.queue.mal.reply" })
public void asyncReply(BaseResponse response) {
logger.debug(response.getMsg());
ccsQtrtzLogService.updateExecResultById(response.getMsg(), response.isSuccess());
}
}
3.fanout模式配置
3.1.队列配置
<!-- fanout方式:发送到所有绑定的queue中,但每个queue只发一次 -->
<rabbit:queue name="ccs.queue.fanout1"
<rabbit:queue name="ccs.queue.fanout2"
<rabbit:fanout-exchange name="${rabbitmq.fanout.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.fanout1"
<rabbit:binding queue="ccs.queue.fanout2"
</rabbit:bindings>
</rabbit:fanout-exchange>
3.2.生产者配置
<rabbit:template id="fanoutTemplate" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.fanout.exchange}"
3.3.消费者配置
同2.3
3.4.生产者示例代码
public class MqFanout extends BaseTask
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("fanoutTemplate");
template.convertAndSend((Object) id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
3.5.消费者示例代码
@Component
public class FanoutQueueListener
private static final Logger logger = LoggerFactory.getLogger(FanoutQueueListener.class);
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.fanout1")
public void helloFanout1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.fanout1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.fanout2")
public void helloFanout2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.fanout2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
//返回执行结果(成功,失败)和ID
4.topic模式配置
4.1.队列配置
<rabbit:queue name="ccs.queue.topic1"
<rabbit:queue name="ccs.queue.topic2"
<rabbit:queue name="ccs.queue.other.topic1"
<rabbit:queue name="ccs.queue.other.topic2"
<rabbit:topic-exchange name="${rabbitmq.topic.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.topic1" pattern="ccs.binding.*"/>
<rabbit:binding queue="ccs.queue.topic2" pattern="ccs.binding.*"/>
<rabbit:binding queue="ccs.queue.other.topic1" pattern="ccs.binding.other.*"/>
<rabbit:binding queue="ccs.queue.other.topic2" pattern="ccs.binding.other.*"/>
</rabbit:bindings>
</rabbit:topic-exchange>
4.2.生产者配置
<rabbit:template id="topicTemplate" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.topic.exchange}"
4.3.消费者配置
同2.3
4.4.生产者代码示例
public class MqTopic extends BaseTask
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("topicTemplate");
template.convertAndSend(template.getExchange(), "ccs.binding.test", id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
ccs.binding.test这个消息会发到ccs.binding.*绑定的两个队列中
4.5.消费者代码示例
@Component
public class TopicQueueListener
private static final Logger logger = LoggerFactory.getLogger(TopicQueueListener.class);
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.topic1")
public void helloTopic1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.topic1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.topic2")
public void helloTopic2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.topic2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.other.topic1")
public void helloOtherTopic1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.other.topic1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.other.topic2")
public void helloOtherTopic2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.other.topic2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
}
RabbitMQ注解方式配置说明
1.共通配置
- spring-rabbit使用1.6版本,需要spring 4.2以上才可以支持使用注解方式配置
- 每个项目配置自己的exchange,格式为项目名称简写+exchange,如:
rabbitmq.direct.exchange=ccs.direct.exchange
可以防止队列重名 - routeKey和queue的名称也要加上项目名称简写防止重名
- 例子中传输数据使用了String,实际使用时可以放入任意对象和返回。
- 附件中spring-rabbit.xml为异步回调方式的完整生产者配置
- 生产者配置时,exchange共有三种方式发送消息,含义请参考http://www.360doc.com/content/14/0608/22/834950_384932402.shtml
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
<rabbit:connection-factory id="connectionFactory"
addresses="${rabbitmq.addresses}" username="${rabbitmq.username}"
password="${rabbitmq.password}" channel-cache-size="${rabbitmq.channel.cache.size}"
<rabbit:admin connection-factory="connectionFactory"
<!-- json转换器,消息可以自动根据转换器转换格式,不配置时默认为java序列化,可以自行配置 -->
<bean id="messageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"
#地址,两个rabbitmq服务器之间为镜像队列
rabbitmq.addresses=192.168.5.130:5672,192.168.5.132:5672
rabbitmq.username=test
rabbitmq.password=test
rabbitmq.concurrentConsumers=5
rabbitmq.channel.cache.size=50
#exchange名称
rabbitmq.direct.exchange=ccs.direct.exchange
rabbitmq.fanout.exchange=ccs.fanout.exchange
rabbitmq.topic.exchange=ccs.topic.exchange
2.direct模式配置
2.1.队列配置
队列配置需要在生产者消费者两边同时配置。
如果只在生产者方配置,rabbitmq服务器中无队列时,会导致消费者服务器启动时找不到监听队列报错
<!-- 将queue和routingKey进行绑定 -->
<rabbit:queue name="ccs.queue.sync"
<rabbit:queue name="ccs.queue.async"
<!-- 定义回复queue -->
<rabbit:queue name="ccs.queue.async.reply"
<!-- direct方式:根据routingKey将消息发送到所有绑定的queue中 -->
<rabbit:direct-exchange name="${rabbitmq.direct.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.sync" key="ccs.binding.sync"
<rabbit:binding queue="ccs.queue.async" key="ccs.binding.async"
<rabbit:binding queue="ccs.queue.async.reply" key="ccs.binding.async.reply"
</rabbit:bindings>
</rabbit:direct-exchange>
注:队列分为同步和异步模式,异步模式支持异步回复功能。ccs.queue.sync队列为同步,ccs.queue.async和ccs.queue.async.reply组合为异步。
2.2.生产者配置
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="500"
<property name="multiplier" value="10.0"
<property name="maxInterval" value="10000"
</bean>
</property>
</bean>
<rabbit:template id="template" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.direct.exchange}"
<!-- exchange为direct模式 -->
<rabbit:template id="template" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.direct.exchange}"
retryTemplate为连接失败时的重发队列所用的templete
2.3.消费者配置
<rabbit:annotation-driven
<bean id="rabbitListenerContainerFactory"
class="org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory">
<property name="messageConverter" ref="messageConverter"
<property name="connectionFactory" ref="connectionFactory"
<property name="concurrentConsumers" value="3"
<property name="maxConcurrentConsumers" value="10"
</bean>
2.4.消费者配置
因为测试用的系统使用了quartz来定时发送队列,代码仅提供rabbitmq相关的功能。使用者根据需要自行修改。
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("template");
template.convertAndSend(template.getExchange(), "ccs.binding.async", id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
- ccs.binding.async为队列的bind名称,一个binding可以绑定多个队列,实现广播功能;
- 同步和异步发送部分代码相同
- MessagePostProcessor可以为队列配置一些参数,本例中配置了jobName
- SpringContextHolder为持有spring上下文的静态对象,参考如下方式配置:
SpringContextHolder配置
2.5.消费者代码示例
@Component
public class AsyncQueueListener
/**
* 同步队列
* @param id 任务ID
* @param
@RabbitListener(queues = "ccs.queue.sync")
public void hello(String id, @Header("jobName") String jobName) {
System.out.println("Received request for id " + id);
System.out.println("Received request for job name " + jobName);
}
/**
* 异步队列,SendTo为回复的队列名称
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.async")
@SendTo("ccs.queue.async.reply")
public BaseResponse hello(String id, @Header("jobName") String jobName) {
System.out.println("Received request for id " + id);
System.out.println("Received request for job name " + jobName);
//返回执行结果(成功,失败)和ID
BaseResponse response = new BaseResponse(true, id);
return
以下代码需要放在生产者服务器,监听异步消息返回的队列
@Component
public class AsyncReplyQueueLitener
private Logger logger = LoggerFactory.getLogger(AsyncReplyQueueLitener.class);
@Autowired
private CcsQtrtzLogService ccsQtrtzLogService;
//参数中使用@Header获取mesage
@RabbitListener(queues = { "ccs.queue.async.reply", "ccs.queue.bds.reply", "ccs.queue.etl.reply", "ccs.queue.mal.reply" })
public void asyncReply(BaseResponse response) {
logger.debug(response.getMsg());
ccsQtrtzLogService.updateExecResultById(response.getMsg(), response.isSuccess());
}
}
3.fanout模式配置
3.1.队列配置
<!-- fanout方式:发送到所有绑定的queue中,但每个queue只发一次 -->
<rabbit:queue name="ccs.queue.fanout1"
<rabbit:queue name="ccs.queue.fanout2"
<rabbit:fanout-exchange name="${rabbitmq.fanout.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.fanout1"
<rabbit:binding queue="ccs.queue.fanout2"
</rabbit:bindings>
</rabbit:fanout-exchange>
3.2.生产者配置
<rabbit:template id="fanoutTemplate" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.fanout.exchange}"
3.3.消费者配置
同2.3
3.4.生产者示例代码
public class MqFanout extends BaseTask
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("fanoutTemplate");
template.convertAndSend((Object) id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
3.5.消费者示例代码
@Component
public class FanoutQueueListener
private static final Logger logger = LoggerFactory.getLogger(FanoutQueueListener.class);
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.fanout1")
public void helloFanout1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.fanout1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.fanout2")
public void helloFanout2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.fanout2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
//返回执行结果(成功,失败)和ID
4.topic模式配置
4.1.队列配置
<rabbit:queue name="ccs.queue.topic1"
<rabbit:queue name="ccs.queue.topic2"
<rabbit:queue name="ccs.queue.other.topic1"
<rabbit:queue name="ccs.queue.other.topic2"
<rabbit:topic-exchange name="${rabbitmq.topic.exchange}">
<rabbit:bindings>
<rabbit:binding queue="ccs.queue.topic1" pattern="ccs.binding.*"/>
<rabbit:binding queue="ccs.queue.topic2" pattern="ccs.binding.*"/>
<rabbit:binding queue="ccs.queue.other.topic1" pattern="ccs.binding.other.*"/>
<rabbit:binding queue="ccs.queue.other.topic2" pattern="ccs.binding.other.*"/>
</rabbit:bindings>
</rabbit:topic-exchange>
4.2.生产者配置
<rabbit:template id="topicTemplate" message-converter="messageConverter"
connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"
exchange="${rabbitmq.topic.exchange}"
4.3.消费者配置
同2.3
4.4.生产者代码示例
public class MqTopic extends BaseTask
@Override
protected void execute(final ScheduleJob scheduleJob, final String id) {
RabbitTemplate template = (RabbitTemplate) SpringContextHolder.getBean("topicTemplate");
template.convertAndSend(template.getExchange(), "ccs.binding.test", id, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("jobName", scheduleJob.getName());
return
ccs.binding.test这个消息会发到ccs.binding.*绑定的两个队列中
4.5.消费者代码示例
@Component
public class TopicQueueListener
private static final Logger logger = LoggerFactory.getLogger(TopicQueueListener.class);
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.topic1")
public void helloTopic1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.topic1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.topic2")
public void helloTopic2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.topic2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.other.topic1")
public void helloOtherTopic1(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.other.topic1");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
/**
*
* @param id 任务ID
* @param type 任务名称
* @return
@RabbitListener(queues = "ccs.queue.other.topic2")
public void helloOtherTopic2(String id, @Header("jobName") String jobName) {
logger.debug("Received request for queue {}", "ccs.queue.other.topic2");
logger.debug("Received request for id {}", id);
logger.debug("Received request for job name {}", jobName);
}
}