RabbitMQ之(三)多种消息模型实战


在RabbitMQ的核心组件交换机中有4种典型的消息模式,即HeadersExchange,FanoutExchange,DirectExchange ,TopicExchange的四种模式,生产环境中,常用后面三种。本节将讲述下面几种

基于FanoutExchange的消息模型实战

在这里插入图片描述
在这里插入图片描述

FanoutExchange具有广播的作用,当消息进入这个中转站的时候,交换机会检查哪个队列跟自己绑定一起的,找到相应的队列后,由队列对应的消费者进行监听消费。
就是一对多的原理
还是在RabbitMQConfig下添加交换机,路由

package com.learn.boot.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.BindingResult;

/** zlx
 *   RabbitMQ自定义注入配置Bean相关组件
 */
@Configuration
public class RabbitmqConfig {
    private static final Logger log= LoggerFactory.getLogger(RabbitmqConfig.class);

    // 自动设置RabbitMQ的连接工厂实例
    @Autowired
    private CachingConnectionFactory connectionFactory;
    // 自动设置消息监听器所在的容器工厂配置类实例
    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;


    /**
     * 下面为单一消费者实例的配置
     * @return
     */
    @Bean(name = "singleListenerContainer")
    public SimpleRabbitListenerContainerFactory listenerContainer(){
        // 定义消息监听器所在的容器工厂
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 设置容器工厂所用的实例
        factory.setConnectionFactory(connectionFactory);
        // 设置消息在传输中的格式,在这里采用JSON的格式进行传输
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        // 设置并发消费者实例的初始数量,在这里为1个
        factory.setConcurrentConsumers(1);
        // 设置并发消费者实例的最大数量,在这里为1个
        factory.setMaxConcurrentConsumers(1);
        // 设置并发消费者实例中每个实例拉取的消息数量,在这里为1个
        factory.setPrefetchCount(1);
        return factory;
    }

    /**
     *下面为多个消费者实例的配置,主要是针对高并发业务场景的配置
     * @return
     */
    @Bean(name = "multiListenerContainer")
    public SimpleRabbitListenerContainerFactory multiListenerContainer(){
        // 定义消息监听器所在的容器工厂
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        // 设置容器工厂所用的实例
        factoryConfigurer.configure(factory,connectionFactory);
        // 设置消息在传输中的格式,在这里采用JSON的格式进行传输
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        // 设置消息的确认消费模式,在这里为NONE,表示不需要确认消费
        factory.setAcknowledgeMode(AcknowledgeMode.NONE);
        // 设置并发消费者实例的初始数量,在这里为10个
        factory.setConcurrentConsumers(10);
        // 设置并发消费者实例的最大数量,在这里为15个
        factory.setMaxConcurrentConsumers(15);
        // 设置并发消费者实例中每个实例拉取的消息数量,在这里为10个
        factory.setPrefetchCount(10);
        return factory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(){
        // 设置“发送消息后返回确认信息”
        connectionFactory.setPublisherReturns(true);
        // 构造发送消息组件实例对象
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        // 这里是为了消息确认和手动ACK
        rabbitTemplate.setMandatory(true);
        // 设置消息在传输中的格式,在这里采用JSON的格式进行传输
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        // 发送消息后,如果发送成功,则输出“消息发送成功”的反馈信息
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                log.info("消息发送成功:correlationData({}),ack({}), cause({})", correlationData,ack,cause);
            }
        });
        // 发送消息后,如果发送失败,则输出“消息丢失”的反馈信息
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                log.info("消息丢失:exchange({}),route({}),replyCode ({}),replyText({}),message:{}",exchange,routingKey,replyCode,replyText,
                message);
            }
        });
        // 最终返回RabbitMQ的操作组件实例RabbitTemplate
        return rabbitTemplate;
    }


    // 创建队列
    @Bean(name = "basicQueue")
    public Queue basicQueue() {
    /*
        // durable :是否持久化(宕机以后重新发布)
        // exclusive : 是否排外,当前队列只能被一个消费者消费
        // autoDelete 如果这个队列没有消费者,队列是否被删除
        // arguments 指定当前队列的其他信息
        */
        return new Queue("basicQueue",true,false,false,null);
    }

    @Bean
    public DirectExchange basicExchange(){
        // 跟创建队列一样
        return new DirectExchange("basicExchange",true,false);
    }

    @Bean
    public Binding basicBinding() {
        // 绑定路由key
        return BindingBuilder.bind(basicQueue()).to(basicExchange()).with("basicExchange-basicQueue-key");

    }

    /**创建消息模型FanoutExchange ------------------------------------------------------------------------------**/

    /** FanoutExchange 交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange("fanoutExchange",true,false);
    }

    //创建队列1
    @Bean(name = "fanoutQueueOne")
    public Queue fanoutQueueOne(){
        return new Queue("fanoutQueueOne",true,false,false,null);
    }

    //创建队列2
    @Bean(name = "fanoutQueueTwo")
    public Queue fanoutQueueTwo(){
        return new Queue("fanoutQueueTwo",true,false,false,null);
    }
    //创建绑定1
    @Bean
    public Binding fanoutBindingOne(){
        return BindingBuilder.bind(fanoutQueueOne()).to(fanoutExchange());
    }
    //创建绑定2
    @Bean
    public Binding fanoutBindingTwo(){
        return BindingBuilder.bind(fanoutQueueTwo()).to(fanoutExchange());
    }
}

    @RequestMapping("/rabbitTestFanoutExchange")
    public ResultVo rabbitTestFanoutExchange(@RequestBody User user) {
        // 注意这里不需要指定路由key了,绑定交换机就行
        rabbitTemplate.convertAndSend("fanoutExchange", "", user, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息的持久化模式
                messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置消息的类型(在这里指定消息类型为Person类型)
                messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,User.class);
                //返回消息实例
                return message;
            }
        });
        log.info("生产者发送对象消息{}",user);
        return ResultVo.success("生产者发送信息成功");
    }

    @RabbitListener(queues = "fanoutQueueOne",containerFactory = "singleListenerContainer")
    public void receiveFanoutResultOne(@Payload User user){
        try {
            log.info("基本消息模型-消费者1-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("基本消息模型-消费者1-发生异常:",e.fillInStackTrace());
        }
    }

    @RabbitListener(queues = "fanoutQueueTwo",containerFactory = "singleListenerContainer")
    public void receiveFanoutResultTwo(@Payload User user){
        try {
            log.info("消息模型-消费者2-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("基本消息模型-消费者2-发生异常:",e.fillInStackTrace());
        }
    }

在这里插入图片描述
这种模式适用于业务数据需要广播式的传播,比如用户操作写日志,将用户操作的日志封装成实体类,并将其序列化

基于DirectExchange的消息模型实战

这是最正规的消息模式,这个必须交换机和路由绑定,才能把消息发送到队列。
在这里插入图片描述
这应该是RabbitMQ最简单的消息模型,在上面的基础上,绑定一个固有的路由key就行了

    /**创建消息模型directExchange----------------------------------------------------------------- **/
    //创建交换机directExchange
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange("directExchange",true,false);
    }
    //创建队列1
    @Bean(name = "directQueueOne")
    public Queue directQueueOne(){
        return new Queue("directQueueOne",true);
    }
    //创建队列2
    @Bean(name = "directQueueTwo")
    public Queue directQueueTwo(){
        return new Queue("directQueueOne",true);
    }
    //创建绑定1
    @Bean
    public Binding directBindingOne(){
        return BindingBuilder.bind(directQueueOne()).to(directExchange()).
                with("directExchange-key-one");
    }
    //创建绑定2
    @Bean
    public Binding directBindingTwo(){
        return BindingBuilder.bind(directQueueTwo()).to(directExchange()).
                with("directExchange-key-two");
    }
  @RequestMapping("/rabbitTestDirectExchange")
    public ResultVo rabbitTestDirectExchange(@RequestBody User user) {
        // 注意这里不需要指定路由key了,绑定交换机就行
        rabbitTemplate.convertAndSend("directExchange", "directExchange-key-one", user, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息的持久化模式
                messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置消息的类型(在这里指定消息类型为User类型)
                messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,User.class);
                //返回消息实例
                return message;
            }
        });
        log.info("生产者发送对象消息{}",user);
        return ResultVo.success("生产者发送信息成功");
    }

    @RequestMapping("/rabbitTestDirectExchangeTwo")
    public ResultVo rabbitTestDirectExchangeTwo(@RequestBody User user) {
        // 注意这里不需要指定路由key了,绑定交换机就行
        rabbitTemplate.convertAndSend("directExchange", "directExchange-key-two", user, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息的持久化模式
                messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置消息的类型(在这里指定消息类型为User类型)
                messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,User.class);
                //返回消息实例
                return message;
            }
        });
        log.info("生产者发送对象消息{}",user);
        return ResultVo.success("生产者发送信息成功");
    }
 @RabbitListener(queues = "directQueueOne",containerFactory = "singleListenerContainer")
    public void receiveDirectQueueOne(@Payload User user){
        try {
            log.info("direct消息模型-消费者1-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("direct消息模型-消费者1-发生异常:",e.fillInStackTrace());
        }
    }

    @RabbitListener(queues = "directQueueTwo",containerFactory = "singleListenerContainer")
    public void receiveDirectQueueTwo(@Payload User user){
        try {
            log.info("direct消息模型-消费者2-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("direct消息模型-消费者2-发生异常:",e.fillInStackTrace());
        }
    }

指定路由key:directExchange-key-one
在这里插入图片描述
指定路由key:directExchange-key-two
在这里插入图片描述

基于TopicExchange的消息模型实战

在这里插入图片描述


    /**创建消息模型topicExchange **/
//创建交换机topicExchange
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange("topicExchange", true,false);
    }
    //创建队列1
    @Bean(name = "topicQueueOne")
    public Queue topicQueueOne(){
        return new Queue("topicQueueOne",true);
    }
    //创建队列2
    @Bean(name = "topicQueueTwo")
    public Queue topicQueueTwo(){
        return new Queue("topicQueueTwo",true);
    }
    //创建绑定,含通配符*的路由
    @Bean
    public Binding topicBindingOne(){
        return BindingBuilder.bind(topicQueueOne()).to(topicExchange()).
                with("*.red.*");
    }
    //创建绑定,含通配符#的路由
    @Bean
    public Binding topicBindingTwo(){
        return BindingBuilder.bind(topicQueueTwo()).to(topicExchange()).
                with("fast.#");
    }
   @RequestMapping("/rabbitTestTopicExchange1")
    public ResultVo rabbitTestRabbitTestTopicExchangeOne(@RequestBody User user) {
        // 这里使用通配符
        rabbitTemplate.convertAndSend("topicExchange", "slow.red.dog", user, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息的持久化模式
                messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置消息的类型(在这里指定消息类型为User类型)
                messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,User.class);
                //返回消息实例
                return message;
            }
        });
        log.info("生产者发送对象消息{}",user);
        return ResultVo.success("生产者发送信息成功");
    }

    @RequestMapping("/rabbitTestTopicExchange2")
    public ResultVo rabbitTestRabbitTestTopicExchangeTwo(@RequestBody User user) {
        // 这里使用通配符#
        rabbitTemplate.convertAndSend("topicExchange", "fast.red.monkey", user, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //获取消息的属性
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息的持久化模式
                messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置消息的类型(在这里指定消息类型为User类型)
                messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,User.class);
                //返回消息实例
                return message;
            }
        });
        log.info("生产者发送对象消息{}",user);
        return ResultVo.success("生产者发送信息成功");
    }
    @RabbitListener(queues = "topicQueueOne",containerFactory = "singleListenerContainer")
    public void receiveTopicQueueOne(@Payload User user){
        try {
            log.info("topic消息模型-消费者topicQueueOne-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("topic消息模型-消费者topicQueueOne-发生异常:",e.fillInStackTrace());
        }
    }


    @RabbitListener(queues = "topicQueueTwo",containerFactory = "singleListenerContainer")
    public void receiveTopicQueueTwo(@Payload User user){
        try {
            log.info("topic消息模型-消费者topicQueueTwo-监听消费消息:{} ",user);
        }catch (Exception e){
            log.error("topic消息模型-消费者topicQueueTwo-发生异常:",e.fillInStackTrace());
        }
    }

这种消息模型,最大的特点就是支持通配路由,以*和#作为通配符,从而绑定不同的队列,*表示一个特定的单词,而#表示任意
slow.red.dog
在这里插入图片描述

fast.red.monkey
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值