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接收了,第二條消息兩個消費者都接收了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章