RabbitMQ注解方式配置说明

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 message;
            }
        });
    }
  • ccs.binding.async为队列的bind名称,一个binding可以绑定多个队列,实现广播功能;
  • 同步和异步发送部分代码相同
  • MessagePostProcessor可以为队列配置一些参数,本例中配置了jobName
  • SpringContextHolder为持有spring上下文的静态对象,参考如下方式配置:
    SpringContextHolder配置
2.5.消费者代码示例
@Component
public 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;
    }
}

以下代码需要放在生产者服务器,监听异步消息返回的队列

@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 message;
            }
        });
    }

}
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 message;
            }
        });
    }

}

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值