RabbitMQ注解方式配置说明

来源:互联网 发布:在线制作淘宝店招 编辑:程序博客网 时间:2024/05/27 16:43

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>
  • 1
  • 2
  • 3
  • 4
<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" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
#地址,两个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注:队列分为同步和异步模式,异步模式支持异步回复功能。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}"  />
  • 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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;            }        });    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 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);        //返回执行结果(成功,失败)和ID        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;    //参数中使用@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());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.2.生产者配置

<rabbit:template id="fanoutTemplate" message-converter="messageConverter"    connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"     exchange="${rabbitmq.fanout.exchange}"  />
  • 1
  • 2
  • 3

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;            }        });    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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);        //返回执行结果(成功,失败)和ID    }}
  • 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4.2.生产者配置

<rabbit:template id="topicTemplate" message-converter="messageConverter"    connection-factory="connectionFactory" reply-timeout="2000" retry-template="retryTemplate"     exchange="${rabbitmq.topic.exchange}"  />
  • 1
  • 2
  • 3

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;            }        });    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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