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" /><bean id="messageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
#地址,两个rabbitmq服务器之间为镜像队列rabbitmq.addresses=192.168.5.130:5672,192.168.5.132:5672rabbitmq.username=testrabbitmq.password=testrabbitmq.concurrentConsumers=5rabbitmq.channel.cache.size=50#exchange名称rabbitmq.direct.exchange=ccs.direct.exchangerabbitmq.fanout.exchange=ccs.fanout.exchangerabbitmq.topic.exchange=ccs.topic.exchange
2.direct模式配置
2.1.队列配置
队列配置需要在生产者消费者两边同时配置。
如果只在生产者方配置,rabbitmq服务器中无队列时,会导致消费者服务器启动时找不到监听队列报错
<rabbit:queue name="ccs.queue.sync" /><rabbit:queue name="ccs.queue.async" /><rabbit:queue name="ccs.queue.async.reply" /><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}" /><rabbit:template id="template" message-converter="messageConverter" connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate" exchange="${rabbitmq.direct.exchange}" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
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 message; } }); }
- ccs.binding.async为队列的bind名称,一个binding可以绑定多个队列,实现广播功能;
- 同步和异步发送部分代码相同
- MessagePostProcessor可以为队列配置一些参数,本例中配置了jobName
- SpringContextHolder为持有spring上下文的静态对象,参考如下方式配置:
SpringContextHolder配置
2.5.消费者代码示例
@Componentpublic class AsyncQueueListener { /** * 同步队列 * @param id 任务ID * @param type 任务名称 */ @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); BaseResponse response = new BaseResponse(true, id); return response; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
以下代码需要放在生产者服务器,监听异步消息返回的队列
@Componentpublic class AsyncReplyQueueLitener { private Logger logger = LoggerFactory.getLogger(AsyncReplyQueueLitener.class); @Autowired private CcsQtrtzLogService ccsQtrtzLogService; @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.队列配置
<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 message; } }); }}
3.5.消费者示例代码
@Componentpublic 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); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
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 message; } }); }}
ccs.binding.test这个消息会发到ccs.binding.*绑定的两个队列中
4.5.消费者代码示例
@Componentpublic 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); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59