RabbitMQ之交換器的三種模式

交換器(exchange)的最大作用一方面在於接收生產者的信息,另一方面在於發送消息到不同的隊列,RabbitMQ中交換器被分爲三類:fanout,topic,director
RabbitMQ消息模型的核心理念:發佈者是將消息直接發送給交換機,由交換機來決定消息是發送到哪個隊列,或者是忽略消息。發佈者(producer)只需要把消息發送給一個交換機(exchange)。交換機非常簡單,它一邊從發佈者方接收消息,一邊把消息推送到隊列。

在這裏插入圖片描述

1.廣播模式(fanout)

廣播模式:生產的每一條消息,由所有消費者進行處理操作
666
圖片參考自網絡

消費者程序

生產者交換器核心代碼

 //信道綁定交換器
 channel.exchangeDeclare(EXCHANGE_NAME,"fanout");

poducer.class

public class MessageProducerfount {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange";
    public static void main(String[] args) throws IOException, TimeoutException {
        //創建連接工廠
        ConnectionFactory factory=new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection=factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel=connection.createChannel();
        //信道進行交換器類型指定
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        //在開始前獲取一下當前時間,方便統計消息全部進入隊列所需的時間
        long start=System.currentTimeMillis();
        for (int i=0;i<10;i++){
            String message="sjw"+i;
            //basicPublish(exchange,隊列名稱,屬性,參數.getbyte())
            channel.basicPublish(EXCHANGE_NAME,"", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());
        }
        //結束時間
        long end=System.currentTimeMillis();
        //輸出所需時間
        System.out.println("進入隊列總共耗時:"+(end-start));
        //關閉信道
        channel.close();
        //關閉連接
        connection.close();
    }
}

消費者程序

消費者核心代碼

//信道綁定交換器
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
//信道交換器綁定,綁定相應的隊列,消費者從隊列中取出數據進行處理
 //第一個參數是隊列名稱,第二個是交換器名稱,第三個rountingkey
channel.exchangeBind(queuename,EXCHANGE_NAME,"");

consumer.class

public class MessageConsumer1 {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection = factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel = connection.createChannel();
        //從信道中尋找隊列名稱
       String queuename=channel.queueDeclare().getQueue();
        //信道設置,必須與要對應接收的隊列設置一模一樣,有差別則無法接收你想要的信道
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
        //交換器Bind隊列,綁定相應的隊列,消費者從隊列中取出數據進行處理
        //第一個參數是隊列名稱,第二個是交換器名稱,第三個rountingkey
        channel.queueBind(queuename,EXCHANGE_NAME,"");
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //信道交給consumer進行內容接收處理
        channel.basicConsume(queuename,consumer);
        while (true) {  //消費者程序運行開着 如果生產者新增了數據會自動獲取
            // nextDelivery是一個阻塞方法(內部實現其實是阻塞隊列的take方法)
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[消費者A:]"+"[消息]" + message);
        }

    }
}

消息生產,觀察exchange
在這裏插入圖片描述

打開三個消費者
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

發現三個消費者都在同時處理生產者產生的消息,廣播模式測試成功!!!

2.直連模式(direct)

直連模式:任何發送到Direct Exchange的消息都會被轉發到RouteKey中指定的Queue。只有key匹配上了,這個隊列的消費者才能進行消費操作

在這裏插入圖片描述

生產者程序

核心代碼

channel.exchangeDeclare(EXCHANGE_NAME,"direct");
channel.basicPublish(EXCHANGE_NAME,"sjw-key", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());

puducer.class

public class MessageProducerfount {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange.direct";

    public static void main(String[] args) throws IOException, TimeoutException {
        //創建連接工廠
        ConnectionFactory factory=new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection=factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel=connection.createChannel();
        //信道進行交換器類型指定
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        //在開始前獲取一下當前時間,方便統計消息全部進入隊列所需的時間
        long start=System.currentTimeMillis();
        for (int i=0;i<10;i++){
            String message="sjw"+i;
            //basicPublish(exchange,隊列名稱,屬性,參數.getbyte())
            channel.basicPublish(EXCHANGE_NAME,"sjw-key", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());
        }
        //結束時間
        long end=System.currentTimeMillis();
        //輸出所需時間
        System.out.println("進入隊列總共耗時:"+(end-start));
        //關閉信道
        channel.close();
        //關閉連接
        connection.close();
    }
}

消費者程序

核心代碼

channel.exchangeDeclare(EXCHANGE_NAME,"direct");
 channel.queueBind(queuename,EXCHANGE_NAME,"sjw-key");

consumer.class

public class MessageConsumer2 {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange.direct";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection = factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel = connection.createChannel();
        //從信道中尋找隊列名稱
        String queuename=channel.queueDeclare().getQueue();
        //信道設置,必須與要對應接收的隊列設置一模一樣,有差別則無法接收你想要的信道
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        //信道交換器綁定,綁定相應的隊列,消費者從隊列中取出數據進行處理
        //第一個參數是隊列名稱,第二個是交換器名稱,第三個rountingkey
        channel.queueBind(queuename,EXCHANGE_NAME,"sjw-key");
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //信道交給consumer進行內容接收處理
        channel.basicConsume(queuename,consumer);
        while (true) {  //消費者程序運行開着 如果生產者新增了數據會自動獲取
            // nextDelivery是一個阻塞方法(內部實現其實是阻塞隊列的take方法)
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[消費者B:]"+"[消息]" + message);
        }

    }
}

此時啓動三個消費者,只有B的與生產者key匹配
在這裏插入圖片描述
只有消費者B可以接收生產者產生的消息
在這裏插入圖片描述直連模式成功!!!

3.主題模式(topic)

主題模式:主題模式更像是廣播模式和直連模式的結合體.根據自定義的規則分配rountingkey給不同的隊列,讓對應key的隊列進行處理.這種模式常用於RabbitMQ.

例如:我們讓模2=0的數字在消費者B出現,其餘的在消費者A出現

生產者代碼

public class MessageProducerfount {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange.topic";

    public static void main(String[] args) throws IOException, TimeoutException {
        //創建連接工廠
        ConnectionFactory factory=new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection=factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel=connection.createChannel();
        //信道進行交換器類型指定
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        //在開始前獲取一下當前時間,方便統計消息全部進入隊列所需的時間
        long start=System.currentTimeMillis();
        for (int i=0;i<10;i++){
            String message="sjw"+i;
            //basicPublish(exchange,隊列名稱,屬性,參數.getbyte())
            if (i%2==0) {
                channel.basicPublish(EXCHANGE_NAME, "sjw-key-B", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
            }else {
                channel.basicPublish(EXCHANGE_NAME, "sjw-key-A", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
            }
        }
        //結束時間
        long end=System.currentTimeMillis();
        //輸出所需時間
        System.out.println("進入隊列總共耗時:"+(end-start));
        //關閉信道
        channel.close();
        //關閉連接
        connection.close();
    }
}

消費者代碼
消費者A

public class MessageConsumer1 {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange.topic";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection = factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel = connection.createChannel();
        //從信道中尋找隊列名稱
       String queuename=channel.queueDeclare().getQueue();
        //信道設置,必須與要對應接收的隊列設置一模一樣,有差別則無法接收你想要的信道
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        //交換器Bind隊列,綁定相應的隊列,消費者從隊列中取出數據進行處理
        //第一個參數是隊列名稱,第二個是交換器名稱,第三個rountingkey
        channel.queueBind(queuename,EXCHANGE_NAME,"sjw-key-A");
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //信道交給consumer進行內容接收處理
        channel.basicConsume(queuename,consumer);
        while (true) {  //消費者程序運行開着 如果生產者新增了數據會自動獲取
            // nextDelivery是一個阻塞方法(內部實現其實是阻塞隊列的take方法)
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[消費者A:]"+"[消息]" + message);
        }

    }
}

消費者B

public class MessageConsumer2 {
    //RabbitMQ服務所在地址
    public final static String HOST="192.168.74.142";
    //RabbitMQ端口
    public final static int PORT=5672;
    //RabbitMQ登陸用戶名
    public final static String USERNAME="sjw";
    //RabbitMQ登陸密碼
    public final static String PASSWORD="123";
    //隊列名稱
    public final static String EXCHANGE_NAME="sjw.exchange.topic";
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(HOST);
        factory.setPort(PORT);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost("sjw.virtual");
        //獲取連接
        Connection connection = factory.newConnection();
        //獲取信道,可以有多個信道
        Channel channel = connection.createChannel();
        //從信道中尋找隊列名稱
        String queuename=channel.queueDeclare().getQueue();
        //信道設置,必須與要對應接收的隊列設置一模一樣,有差別則無法接收你想要的信道
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        //信道交換器綁定,綁定相應的隊列,消費者從隊列中取出數據進行處理
        //第一個參數是隊列名稱,第二個是交換器名稱,第三個rountingkey
        channel.queueBind(queuename,EXCHANGE_NAME,"sjw-key-B");
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //信道交給consumer進行內容接收處理
        channel.basicConsume(queuename,consumer);
        while (true) {  //消費者程序運行開着 如果生產者新增了數據會自動獲取
            // nextDelivery是一個阻塞方法(內部實現其實是阻塞隊列的take方法)
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[消費者B:]"+"[消息]" + message);
        }

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