RabbitMQ

RabbitMQ消息模型

RabbitMQ官方提供了5个不同的Demo示例,对应了不同的消息模型:

  • 简单模型:一个消费者,一个发布者
  • Work模型:多个消费者绑定到一个队列,同一条消息只会被一个消费者处理
  • 广播模型:Fanout交换机将消息路由给每一个与之绑定的队列
  • 路由模型:Direct交换机根据RoutingKey判断路由给哪个队列
  • 主题模型:Topic交换机接收的消息RoutingKey必须是多个单词,以 `**.**` 分割

    导依赖

    <!--AMQP依赖,包含RabbitMQ-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

    改配置

    spring:
      rabbitmq:
        host: 192.168.150.101 # 主机名,mq所在服务器
        port: 5672 # 端口
        virtual-host: / # 虚拟主机
        username: itcast # 用户名
        password: 123321 # 密码

    Queue 简单队列模型

     发布者端

        @Autowired
        private RabbitTemplate rabbitTemplate;
        @Test
        public void testSimpleQueue() {
            // 队列名称
            String queueName = "simple.queue";
            // 消息
            String message = "hello, spring amqp!";
            // 发送消息
            rabbitTemplate.convertAndSend(queueName, message);
        }

     消费者端

    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SpringRabbitListener {
        @RabbitListener(queues = "simple.queue")//指定队列名监听
        public void listenSimpleQueueMessage(String msg) {
            System.out.println("spring 消费者接收到消息:【" + msg + "】");
        }
    }

    WorkQueue​​​​​​​工作队列

     Work queue,工作队列模型,可以提高消息处理速度,避免队列消息堆积

     发布者端

    @Test
    public void testWorkQueue() throws InterruptedException {
        // 队列名称
        String queueName = "simple.queue";
        // 消息
        String message = "hello, message_";
        // 发送消息
        rabbitTemplate.convertAndSend(queueName, message + i);
    }

    消费者端

    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue1(String msg) throws InterruptedException {
        System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
        Thread.sleep(20);
    }
    
    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue2(String msg) throws InterruptedException {
        System.err.println("消费者2........接收到消息:【" + msg + "】" + LocalTime.now());
        Thread.sleep(200);
    }

    因为默认是均分的,如果一个服务器很慢,则会影响整个系统执行效率,做到能者多劳,在spring中有一个简单的配置,可以解决这个问题。我们修改consumer服务的application.yml文件,添加配置:

    spring:
      rabbitmq:
        listener:
          simple:
            prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

    发布/订阅模型

    发布订阅模式与之前案例的区别就是允许将同一消息发送给多个消费者。

    模型

    在consumer消费者中创建一个类,声明队列和交换机:

    @Configuration
    public class FanoutConfig {
         //声明这是一个广播类型的交换机
        @Bean
        public FanoutExchange fanoutExchange(){
            return new FanoutExchange("exchange.fanout");//广播Fanout类型交换机
        }
    
        //第1个队列
        @Bean
        public Queue fanoutQueue1(){
            return new Queue("fanout.queue1");
        }
    
        //绑定队列和交换机 
        @Bean
        public Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
            return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
        }
    
       //第2个队列
        @Bean
        public Queue fanoutQueue2(){
            return new Queue("fanout.queue2");
        }
    
        //绑定队列和交换机
        @Bean
        public Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
            return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
        }
    }

    发布者端

    @Test
    public void testFanoutExchange() {
        // 队列名称
        String exchangeName = "exchange.fanout";
        // 消息
        String message = "hello, everyone!";
        rabbitTemplate.convertAndSend(exchangeName, "", message);
    }

    消费者端

    @RabbitListener(queues = "fanout.queue1")
    public void listenFanoutQueue1(String msg) {
        System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
    }
    
    @RabbitListener(queues = "fanout.queue2")
    public void listenFanoutQueue2(String msg) {
        System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
    }

    路由模型

    我们希望不同的消息被不同的队列消费,这时就要用到Direct类型的Exchange。

    基于注解声明队列和交换机

     发布者端

    @Test
    public void testSendDirectExchange() {
        // 交换机名称
        String exchangeName = "exchange.direct";
        // 消息
        String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";
        // 发送消息
        rabbitTemplate.convertAndSend(exchangeName, "red", message);
    }

     消费者端

    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "direct.queue1"),
        exchange = @Exchange(name = "exchange.direct", type = ExchangeTypes.DIRECT),
        key = {"red", "blue"}//只消费带有,red或者blue的消息
    ))
    public void listenDirectQueue1(String msg){
        System.out.println("消费者接收到direct.queue1的消息:【" + msg + "】");
    }
    
    
    
    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "direct.queue2"),
        exchange = @Exchange(name = "exchange.direct", type = ExchangeTypes.DIRECT),
        key = {"red", "yellow"}//只消费带有,red或者yellow的消息
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("消费者接收到direct.queue2的消息:【" + msg + "】");
    }

     主题模型

    发布者端

    @Test
    public void testSendTopicExchange() {
        // 交换机名称
        String exchangeName = "exchange.topic";
        // 消息
        String message = "喜报!孙悟空大战哥斯拉,胜!";
        // 发送消息
        rabbitTemplate.convertAndSend(exchangeName, "china.news", message);
    }

     消费者端

    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "topic.queue1"),
        exchange = @Exchange(name = "exchange.topic", type = ExchangeTypes.TOPIC),
        key = "china.#"
    ))
    public void listenTopicQueue1(String msg){
        System.out.println("消费者接收到topic.queue1的消息:【" + msg + "】");
    }
    
    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "topic.queue2"),
        exchange = @Exchange(name = "exchange.topic", type = ExchangeTypes.TOPIC),
        key = "#.news"
    ))
    public void listenTopicQueue2(String msg){
        System.out.println("消费者接收到topic.queue2的消息:【" + msg + "】");
    }

     消息转换器

    默认实现是SimpleMessageConverter,基于JDKObjectOutputStream完成序列化。发送对象类型时,会乱码,如果要修改只需要定义一个MessageConverter 类型的Bean即可。推荐用JSON方式序列化,步骤如下:

    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.9.10</ version >
    </dependency>
    

    在配置类声明转换器

    @Bean
    public MessageConverter jsonMessageConverter(){
       return new Jackson2JsonMessageConverter();
    }
    

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值