rabbitmq-常用的五种工作模式

参考文章:https://blog.csdn.net/hellozpc/article/details/81436980

安装时需注意:

1.需要安装erlang环境,配置环境变量。

2.需要注意RabbitMQ对应的erLang的版本,版本不对会出错。

3.我的代码,RabbitMQ版本为 最新版本3.8.3,消费者代码有所不同

项目下载地址:

https://github.com/prettycharacter/myRabbitMQ.git

五种配置模式的实现

准备工作:

1.引入RabbitMQ客户端依赖
<dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.9.0</version>
</dependency>
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.创建连接类ConnectionUtil
package com.ampq.myrabbitmq.utils;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * @author xpf
 * @date 2020/5/14 14:35
 */
public class ConnectionUtil {
    public static Connection getConnection() throws Exception {
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("localhost");
        //端口
        factory.setPort(5672);
        //设置账号信息,用户名、密码、vhost
        factory.setVirtualHost("/");
        //自己定义的用户.
        factory.setUsername("mqadmin");
        factory.setPassword("mqadmin123");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        return connection;
    }

}

1.简单队列

生产者将消息发送到队列,消费者从队列中获取消息

在这里插入图片描述

生产者发送消息
public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //从连接中创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //消息内容
        for (int i = 0; i < 10; i++) {
            String message = "Hello World+" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println("send:" + message);
            Thread.sleep(10);
        }
        //关闭通道和连接
        channel.close();
        connection.close();
    }
//输出:
send:Hello World

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                System.out.println("[Receive]:" + message);
            }
        };
        channel.basicConsume(QUEUE_NAME, consumer);
    }
//输出:
[Receive]:Hello World

2.Work模式

一个生产者,多个消费者, 一个消息只能被一个消费者获取。

在这里插入图片描述

①轮询分发消息

轮询(Round-Robin)分发 :使用任务队列的优点之一就是可以轻易的并行工作。默认情况下,RabbitMQ将逐个发送消息到在序列中的下一个消费者(而不考虑每个任务的时长等等,且是提前一次性分配,并非一个一个分配)。平均每个消费者获得相同数量的消息。这种方式分发消息机制称为轮询。

运行测试时先启动消费者监听。

消费者接收消息
//消费者1
private final static String QUEUE_NAME = "q_test_2";
public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                System.out.println("[Receive]:" + message);
                 try {
                    Thread.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        };
        //监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
//消费者2
private final static String QUEUE_NAME = "q_test_2";
public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                System.out.println("[Receive]:" + message);
                 try {
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        };

        //监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME,true,consumer);
    }
生产者发送消息
public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //从连接中创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //消息内容
        for (int i = 0; i < 100; i++) {
            String message = "Hello World+" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println("send:" + message);
            Thread.sleep(10);
        }
        //关闭通道和连接
        channel.close();
        connection.close();
    }

上面测试发现:两个消费者处理的消息一样多

②公平分发消息(能者多劳)

公平分发 :上面的分配法方式也还行,但是有个问题就是:有两个消费者,都能处理B消息,消费者1号非常繁忙,消费者2号空闲,但是rabbitMQ并不知道这个情况,只会轮询发送消息,造成了不均衡的情况。

解决方式:我们通过设置 basicQos(prefetchCount=1)方法,限制RabbitMQ只发一条消息给同一个消费者,消费者处理完消息,有了反馈,才发送第二次消息。

需要注意:关闭自动应答,改为手动应答。

消费者接收消息
 public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //同一时刻服务器只会发送一条消息
        channel.basicQos(1);
        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                //表示使用手动确认模式
                System.out.println("[Receive]:" + message);
                try {
                    Thread.sleep(10);//两个消费者这里的代码不一样
                }catch (InterruptedException e){
                    e.printStackTrace();
                }finally {
                    //改为手动确认
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        //监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME,false,consumer);
    }
生产者发送消息
生产者代码不变

上面测试发现:睡眠时间长的处理消息少(能者多劳)

③消息的确认模式

模式1:自动确认-只要消费者获取到消息,无论消费者是否执行成功,都认为消息已经消费

模式2:手动确认-消费者获取消息-消息变为不可用状态-消费者成功后反馈-消息消费

channel.basicConsume("",true/false,consumer);

true 表示自动确认


false 表示手动确认
//反馈消息的状态
channel.basicAck(envelope.getDeliveryTag(),false);

3.订阅模式(Publish/Subscribe)

  • 1个生产者-多个消费者
  • 每个消费者都有自己的一个队列
  • 生产者没有将消息直接发送给队列,而是发送到了交换机
  • 每个队列都要绑定到交换机
  • 生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的。
  • 一个消费者队列可以有多个消费者实例,只有其中一个消费者实例会消费。

在这里插入图片描述

生产者发送消息
private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //从连接中创建通道
        Channel channel = connection.createChannel();
        //声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        //消息内容
        String message = "Hello World";
        channel.basicPublish(EXCHANGE_NAME,"",  null, message.getBytes());
        System.out.println("send:" + message);
        //关闭通道和连接
        channel.close();
        connection.close();
    }
//输出:
send:Hello World

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
private final static String QUEUE_NAME = "test_queue_1";

    private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        //同一时刻服务器只会发送一条消息
        channel.basicQos(1);
        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                //表示使用手动确认模式
                System.out.println("[Receive]:" + message);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };
        //监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, false, consumer);

    }
//消费者2
private final static String QUEUE_NAME = "test_queue_2";
    private final static String EXCHANGE_NAME = "exchange_fanout";

    public static void main(String[] args) throws Exception {
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        //创建通道
        Channel channel = connection.createChannel();
        //创建队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        //同一时刻服务器只会发送一条消息
        channel.basicQos(1);
        //获取消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "utf-8");
                //表示使用手动确认模式
                System.out.println("[Receive]:" + message);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };
        //监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }

//输出:
[Receive]:Hello World

上面测试发现:同一个消息被多个消费者获取。一个消费者队列可以有多个消费者实例,只有其中一个消费者实例会消费到消息。

4.路由模式

  • 跟订阅模式类似,只不过在订阅模式的基础上加上了类型,订阅模式是分发到所有绑定到交换机的队列,路由模式只分发到绑定在交换机上面指定路由键的队列。
  • 生产者申明一个direct类型交换机,然后发送消息到这个交换机指定路由键。
  • 消费者指定消费这个交换机的这个路由键,即可接收到消息,其他消费者收不到。
    在这里插入图片描述
生产者发送消息
//声明交换机(exchange),direct为交换机类型。
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
//输出:
send:Hello World

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
//绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingtest");//消费者1

//消费者2
 //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routingtest");
//输出:
[Receive]:Hello World

上面测试发现:路由模式只分发到绑定在交换机上面指定路由键的队列

5.主题模式(通配符模式)

  • 将路由键和某模式进行匹配
  • 队列绑定到一个模式上, #匹配一个或者多个词,*匹配一个词。
    在这里插入图片描述
生产者发送消息
 //声明交换机(exchange),direct为交换机类型。
        channel.exchangeDeclare(EXCHANGE_NAME, "topic"); 
//消息key为 routingtest
        channel.basicPublish(EXCHANGE_NAME,"topic.notice.all",  null, message.getBytes());
//输出:
send:Hello World

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
//绑定队列到交换机
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "topic.*");

//消费者2
 //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "topic.#");
//输出:
[Receive]:Hello World

上面测试发现:topic模式可以模糊匹配路由键,只会匹配一个词,#匹配多个词

SpringBoot集成RabbitMQ

SpringBoot集成RabbitMQ比较简单,使用的配置非常少,SpringBoot提供了Spring-boot-starter-amqp对各种消息的支持

准备工作:

1.配置pom文件,引入依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置application.yml文件
//配置rabbitmq的安装地址、端口以及账户信息
spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: mqadmin
    password: xykj.8387
server:
  port: 8888
3.静态常量文件
package com.ampq.myrabbitmq.utils;

/**
 * @author xpf
 * @date 2020/5/18 14:13
 */
public class Constants {
    //简单模式队列名称
    public final static String BOOT_QUEUE_SIMPLE = "boot_queue_simple";
    //work模式队列名称
    public final static String BOOT_QUEUE_WORK = "boot_queue_work";
    //计算能者多劳接收的数量
    public static int RECEIVE_1 = 0;
    public static int RECEIVE_2 = 0;

    //订阅模式
   //队列
    public final static String A_BOOT_QUEUE_PUBLISH = "a_boot_queue_publish";
    public final static String B_BOOT_QUEUE_PUBLISH = "b_boot_queue_publish";
    public final static String C_BOOT_QUEUE_PUBLISH = "c_boot_queue_publish";
    //交换机
    public final static String BOOT_EXCHANGE_PUBLISH = "boot_exchange_publish";

   //topic模式
   //队列
   public final static String BOOT_QUEUE_TOPIC_A = "boot_queue_topic_a";
   public final static String BOOT_QUEUE_TOPIC_B = "boot_queue_topic_b";
   //交换机
   public final static String BOOT_EXCHANGE_TOPIC = "boot_exchange_topic";


}

4.配置队列
package com.ampq.myrabbitmq.springboot.rabbitmq;

import com.ampq.myrabbitmq.utils.Constants;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author xpf
 * @date 2020/5/18 10:09
 */
@Configuration
public class RabbitConfig {

    //简单模式
    @Bean
    public Queue queue() {

        return new Queue(Constants.BOOT_QUEUE_SIMPLE);
    }

    //工作模式
    @Bean
    public Queue queueWork() {

        return new Queue(Constants.BOOT_QUEUE_WORK);
    }
    @Bean("workListenerFactory")
    public RabbitListenerContainerFactory myFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
        containerFactory.setConnectionFactory(connectionFactory);
        //自动ack,没有异常情况下自动发送ack
        //auto 自动确认,默认是Auto
        //MANUAL 手动确认
        //none 不确认,发完自动丢弃
        containerFactory.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //拒绝策略,true回到队列,false是丢弃,默认为true
        containerFactory.setDefaultRequeueRejected(true);
        //默认的prefetchCount是250,效率低
        //设置为1
        containerFactory.setPrefetchCount(1);
        return containerFactory;
    }

    //订阅模式
    //队列
    @Bean
    public Queue aPublishQueue(){
            return new Queue(Constants.A_BOOT_QUEUE_PUBLISH);
    }
    @Bean
    public Queue bPublishQueue(){
            return new Queue(Constants.B_BOOT_QUEUE_PUBLISH);
    }
    @Bean
    public Queue cPublishQueue(){
            return new Queue(Constants.C_BOOT_QUEUE_PUBLISH);
    }
    //交换机
    @Bean
    FanoutExchange fanoutExchange(){
        return new FanoutExchange(Constants.BOOT_EXCHANGE_PUBLISH);
    }
    //绑定交换机
    @Bean
    Binding bindingExchangeA(Queue aPublishQueue,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(aPublishQueue).to(fanoutExchange);
    }
    @Bean
    Binding bindingExchangeB(Queue bPublishQueue,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(bPublishQueue).to(fanoutExchange);
    }
    @Bean
    Binding bindingExchangeC(Queue cPublishQueue,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(cPublishQueue).to(fanoutExchange);
    }

    //topic模式

    //队列
    @Bean
    Queue topicQueueA(){
        return new Queue(Constants.BOOT_QUEUE_TOPIC_A);
    }
    @Bean
    Queue topicQueueB(){
        return new Queue(Constants.BOOT_QUEUE_TOPIC_B);
    }
    //topic交换机
    @Bean
    TopicExchange topicExchange(){
        return new TopicExchange(Constants.BOOT_EXCHANGE_TOPIC);
    }
    //绑定交换机
    @Bean
    Binding bindingTopicExchangeA(Queue topicQueueA,TopicExchange topicExchange){
        return BindingBuilder.bind(topicQueueA).to(topicExchange).with("topic.message.*");
    }
    @Bean
    Binding bindingTopicExchangeB(Queue topicQueueB,TopicExchange topicExchange){
        return BindingBuilder.bind(topicQueueB).to(topicExchange).with("topic.message.#");
    }
}

1.简单模式

之后的代码没有导包路径跟下面一样的

生产者发送消息
package com.ampq.myrabbitmq.springboot.rabbitmq.simple;

import com.ampq.myrabbitmq.utils.Constants;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author xpf
 * @date 2020/5/18 10:15
 */
@Component
public class SimpleSender {

    @Resource
    private AmqpTemplate rabbitTemplate;

    public void send(){
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String context = "hello "+date;
        System.out.println("sender :"+ context);
        //简单队列情况下routingkey即为Q名
        this.rabbitTemplate.convertAndSend(Constants.BOOT_QUEUE_SIMPLE,context);
    }
}

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
package com.ampq.myrabbitmq.springboot.rabbitmq.simple;

import com.ampq.myrabbitmq.utils.Constants;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * @author xpf
 * @date 2020/5/18 10:20
 */
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_SIMPLE)
public class SimpleReceiver {

    @RabbitHandler
    public void process(String hello){
        //接收消息
        System.out.println("receiver:"+ hello);
    }
}
测试代码
package com.ampq.myrabbitmq;

import com.ampq.myrabbitmq.springboot.rabbitmq.simple.SimpleSender;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
class MyRabbitmqApplicationTests {
    @Resource
    private SimpleSender simpleSender;

    @Test
    void contextLoads() {
        simpleSender.send();
    }
}
//输出
...
sender :hello 2020-05-18 10:28:41

2020-05-18 10:28:41.179  INFO 12560 --- [extShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
    
receiver:hello 2020-05-18 10:28:41
...

2.work模式

生产者发送消息
@Component
public class WorkSender {

    @Resource
    private AmqpTemplate rabbitTemplate;

    public void send(int i){
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String context = "hello "+ i +" "+date;
        //简单队列情况下routingkey即为Q名
        this.rabbitTemplate.convertAndSend(Constants.BOOT_QUEUE_WORK,context);
    }
}

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_WORK, containerFactory = "workListenerFactory")
/*
这里需要注意,加上containerFactory就是能者多劳模式,不加就是轮询模式
*/
public class WorkReceiver1 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        Thread.sleep(10);
        Constants.RECEIVE_1++;
        //接收消息
        System.out.println("receiver1:" + hello + " " + Constants.RECEIVE_1);
    }
}

//消费者2
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_WORK,containerFactory = "workListenerFactory")
public class WorkReceiver2 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        Constants.RECEIVE_2++;
        Thread.sleep(20);
        //接收消息
        System.out.println("receiver2:" + hello+" "+Constants.RECEIVE_2);

    }
}
测试代码
 @Test
    void workQueue() throws Exception {
        for (int i = 0; i < 100; i++) {
            workSender.send(i);
        }
    }
//输出
...
//消费者1输出64条
receiver1:hello 97 2020-05-18 15:30:10 64
//消费者2输出34条
receiver2:hello 96 2020-05-18 15:30:10 34
...

3.订阅模式(Publish/subcsribe)

生产者发送消息
@Component
public class PublishSender {

    @Resource
    private AmqpTemplate rabbitTemplate;

    public void send(){
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String context = "publish : "+date;
        //简单队列情况下routingkey即为Q名
        this.rabbitTemplate.convertAndSend(Constants.BOOT_EXCHANGE_PUBLISH,"",context);
    }
}

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
@Component
@RabbitListener(queues = Constants.A_BOOT_QUEUE_PUBLISH)
public class PublishReceiver1 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver1:" + hello);
    }
}

//消费者2
@Component
@RabbitListener(queues = Constants.B_BOOT_QUEUE_PUBLISH)
public class PublishReceiver2 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver2:" + hello);

    }
}

//消费者3
@Component
@RabbitListener(queues = Constants.C_BOOT_QUEUE_PUBLISH)
public class PublishReceiver3 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver3:" + hello);

    }
}
测试代码
 @Test
    void PublishQueue() throws Exception {
        publishSender.send();
    }
//输出
...
receiver2:publish : 2020-05-18 16:04:48
receiver1:publish : 2020-05-18 16:04:48
receiver3:publish : 2020-05-18 16:04:48
...
 //绑定了交换机的队列都收到消息

4.topic模式(通配符)

生产者发送消息
@Component
public class TopicSender {

    @Resource
    private AmqpTemplate rabbitTemplate;

    public void send1(){
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String context = "topic1 : "+date;
        //简单队列情况下routingkey即为Q名
        this.rabbitTemplate.convertAndSend(Constants.BOOT_EXCHANGE_TOPIC,"topic.message.x.y",context);
    }
    public void send2(){
        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String context = "topic2 : "+date;
        //简单队列情况下routingkey即为Q名
        this.rabbitTemplate.convertAndSend(Constants.BOOT_EXCHANGE_TOPIC,"topic.message.x",context);
    }
}

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_TOPIC_A)
public class TopicReceiver1 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver1:" + hello);
    }
}

//消费者2
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_TOPIC_B)
public class TopicReceiver2 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver2:" + hello);

    }
}
测试代码
 /**
     * topic模式测试
     */
    @Test
    void TopicQueue() throws Exception {
        topicSender.send1();
        topicSender.send2();
    }
//输出
...
receiver2:topic1 : 2020-05-18 16:37:02
receiver1:topic2 : 2020-05-18 16:37:02
receiver2:topic2 : 2020-05-18 16:37:02
...
 //第一条消息消费者2接收了,第二条消息两个消费者都接收了

生产者发送消息以后,在RabbitMQ服务端可以看见这条消息。

消费者接受消息
//消费者1
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_TOPIC_A)
public class TopicReceiver1 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver1:" + hello);
    }
}

//消费者2
@Component
@RabbitListener(queues = Constants.BOOT_QUEUE_TOPIC_B)
public class TopicReceiver2 {

    @RabbitHandler
    public void process(String hello) throws Exception {
        //接收消息
        System.out.println("receiver2:" + hello);

    }
}
测试代码
 /**
     * topic模式测试
     */
    @Test
    void TopicQueue() throws Exception {
        topicSender.send1();
        topicSender.send2();
    }
//输出
...
receiver2:topic1 : 2020-05-18 16:37:02
receiver1:topic2 : 2020-05-18 16:37:02
receiver2:topic2 : 2020-05-18 16:37:02
...
 //第一条消息消费者2接收了,第二条消息两个消费者都接收了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值