2.RabbitMQ的5種模式,並使用java進行模擬操作-學習筆記

cxrlover發表於2020-11-28

2. RabbitMQ的5種工作模式

首先把官網介紹放在這裡:https://www.rabbitmq.com/getstarted.html

然後就開始記錄一下學習到的吧!多多指教

2.1 簡單模式

在這裡插入圖片描述

  1. 就是將一個生產者繫結到一個訊息佇列,然後消費者從這個訊息佇列中取訊息進行消費
  2. 在生產者與佇列之間,使用的有預設的交換機

流程

生產者:

  1. 新建Connection工廠 ,需要設定一些屬性(ConnectionFactory)
  2. 使用Connection工廠獲取Connection物件
  3. 使用Connection物件獲取Channel(通道)物件
  4. 通過Channel宣告一個訊息佇列
  5. 傳送訊息
  6. 關閉連線資源

程式碼實現

public class HelloProduct {
    public static void main(String[] args)  throws  Exception{
         //1.得到ConnectionFactory
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("localhost");//預設就是localhost 可以不加該程式碼
        connectionFactory.setPort(5672);//預設就是5672
        // 這裡說明一下,這個路徑,還有賬戶密碼,是自己提前建好的
        connectionFactory.setVirtualHost("/lh");//預設是 /
        connectionFactory.setUsername("ldh");//預設guest
        connectionFactory.setPassword("ldh"); //預設guest
        //2. 獲取Connection
        Connection connection=connectionFactory.newConnection();
        //3.獲取Channel
        Channel channel = connection.createChannel();
        //4.建立佇列
        /**
         * queue(佇列的名稱),  
         * durable(是否持久化),  
         * exclusive (是否是獨享的,表示被該通道獨享),
         * autoDelete (是否自動刪除 如果沒有消費者哪個該佇列就會自動刪除),
         * Map<String, Object> arguments: 佇列的引數設定
         */
        channel.queueDeclare("hello-queue",false,false,false,null);
        // 5.傳送訊息,這裡使用四個引數的方法
        //exchange交換機的名稱, 如果你使用的為Hello模式 那麼交換機的名稱為”“
        //routingKey:路由key    如果你使用的為Hello模式 那麼路由key必須為佇列的名稱
        //props: 訊息的屬性資訊  null
        //body: 表示訊息內容
        String msg = "今天第一天學習RabbitMQ所以速度很慢:"+i;
        channel.basicPublish("", "hello-queue", null, msg.getBytes());
		// 關閉資源
        channel.close();
        connection.close();
    }
}

消費者:

  1. 新建Connection工廠 ,需要設定一些屬性(ConnectionFactory)
  2. 使用Connection工廠獲取Connection物件
  3. 使用Connection物件獲取Channel(通道)物件
  4. 獲取通道中的訊息並通過回撥函式進行處理

程式碼實現

public class HelloConsumer {
    public static void main(String[] args) throws Exception {
        //1.得到ConnectionFactory
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setVirtualHost("/lh");//預設 /
        connectionFactory.setUsername("ldh");//預設guest
        connectionFactory.setPassword("ldh"); //預設guest
        //2. 獲取Connection
        Connection connection=connectionFactory.newConnection();
        //3.獲取Channel
        Channel channel = connection.createChannel();
        //4. 消費訊息
        //String queue, Consumer callback
        //queue:佇列的名稱
        //callback: 回撥函式。
        //boolean autoAck:是否自動回覆
        Consumer consumer=new DefaultConsumer(channel){
            //當獲取到訊息後觸發該方法的執行
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(new String(body));
            }
        };
        // 接收訊息
        channel.basicConsume("hello-queue",true,consumer);
    }
}

1.2 工作模式

在這裡插入圖片描述
跟上邊的模式相差不大,只是增加了一個消費者。
只需要將上邊的消費者程式碼複製一份即可,這裡不在多說了。

1.3 廣播模式(fanout)

在這裡插入圖片描述
這個模式和簡單模式有一些不同的地方:

  1. 這個模式需指定使用 fanout 型別的交換機

除此之外其他大同小異,這裡寫一下流程和程式碼實現

流程

生產者:

  1. 新建ConnctionFactory
  2. 通過ConnectionFactory獲取Connection
  3. 通過Connection物件獲取Channel
  4. 通過Channel物件定義交換機,指定型別為fanout
  5. 通過Channel物件定義訊息佇列
  6. 通過Channel物件對交換機和佇列進行繫結
  7. 傳送訊息
  8. 關閉資源

程式碼

public class PublishProduct {
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory=new ConnectionFactory();
        factory.setUsername("ldh");
        factory.setPassword("ldh");
        factory.setVirtualHost("/lh");
        
        Connection connection=factory.newConnection();
        Channel channel = connection.createChannel();

        //建立交換機
        /**
         * String exchange: 交換機的名稱
         * BuiltinExchangeType type: 交換機的型別
         * 		fanout:廣播模式:只要是繫結到交換機上的佇列都可以收到訊息
         * 		direct:路由模式:  只要符合指定路由key的才可以收到訊息
         *		topic:主題模式;  只要符合指定路由key的才可以收到訊息
         * boolean durable, 是否持久化
         * boolean autoDelete, 是否自動刪除
         * Map<String, Object> arguments 引數
         */
        channel.exchangeDeclare("fanout-exchange", BuiltinExchangeType.FANOUT,false,true,null);

		// 定義訊息佇列
        channel.queueDeclare("fanout_queue1",false,false,false,null);
        channel.queueDeclare("fanout_queue2",false,false,false,null);

        //佇列和互動機進行繫結
        channel.queueBind("fanout_queue1","fanout-exchange","");
        channel.queueBind("fanout_queue2","fanout-exchange","");
        for(int i=0;i<10;i++) {
            channel.basicPublish("fanout-exchange", "", null, (i+"hello pulish exchange").getBytes());
        }
        // 關閉資源
        channel.close();
        connection.close();
    }
}

消費者只需要改變一下繫結的佇列即可,其他不需要改變。這裡不在給出程式碼。

1.4 路由模式 (routing)

在這裡插入圖片描述
通過圖可以看出,這個模式相較於廣播模式而言,在交換機和佇列訊息的傳送上多了一些控制。廣播模式中,交換機傳送一條訊息,所有的繫結的佇列都可以接收到。而在這種模式下,交換機傳送一條訊息,只有滿足條件的佇列,交換機才會傳送。

在程式碼層面,相較於廣播模式,發生了一些改變:

  1. 需要指定交換機模式為 direct 模式
  2. 在交換機和佇列繫結時需要指定 routingkey,不能在是 空字串了
    同一個佇列要繫結多個條件時,需要多次繫結
  3. 傳送訊息的時候需要帶上 routingkey。

這裡只列出不同的程式碼:

// 通過 Channel 物件宣告交換機,型別為 direct
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT,false,true,null);

// 宣告佇列
channel.queueDeclare(QUEUE_NAME1,false,false,false,null);
channel.queueDeclare(QUEUE_NAME2,false,false,false,null);

// 佇列和交換機進行繫結
channel.queueBind(QUEUE_NAME1,EXCHANGE_NAME,"error");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"error");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"info");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"debug");

// 傳送訊息
channel.basicPublish(EXCHANGE_NAME, "info", null, (i+"hello pulish exchange").getBytes());

1.5 萬用字元模式(topics)

在這裡插入圖片描述
從圖中可以看出,萬用字元模式與路由模式十分相似,不同的地方在於:
交換機與佇列的 “路由key” 形式發生了變化。 使用方法與路由模式大同小異
* 和 # 的區別,我在這裡沒有感受到有什麼不同, 都是表示匹配0個或多個字元

與路由模式的不同:

  1. 需要指定交換機模式為 topic 模式
  2. 在於佇列進行繫結的時候需要指定 routingKey 的規則
  3. 在傳送訊息時,需要指定 routingKey

核心程式碼

// 4. 宣告使用的交換機
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC);
// 5. 新建佇列
channel.queueDeclare(queueName1, false, false, false, null);
channel.queueDeclare(queueName2, false, false, false, null);
// 6. 繫結交換機和佇列
channel.queueBind(queueName1, exchangeName, "*.orange");
channel.queueBind(queueName2, exchangeName, "*.*.rabbite");
channel.queueBind(queueName2, exchangeName, "lazy.#");
// 7. 傳送訊息給佇列
String msg = "這是通過topic模式傳送的訊息";
channel.basicPublish(exchangeName, "abc.orange", null, msg.getBytes());

記錄結束!

相關文章