RabbitMQ的基礎使用 —— Direct模式(二)

RabbitMQ的基礎使用 —— Direct模式(一)中,我們已經瞭解了基礎的Direct模式的使用,其中我們發現一個隊列不僅僅可以對應一個路由鍵,它可以同時綁定多個路由鍵。


這裏我們繼續來了解下Rabbit中信道問題,之前RabbitMQ的基礎使用 —— Direct模式(一)中代碼中就是一個連接一個信道,不過我們之前AMQP及RabbitMQ概論中介紹到過,一個連接是可以有很多很多的信道的,這裏我們就來在代碼中看一看。



一個連接多個信道怎麼來設置呢,這裏我們可以簡單的把利用連接Connection創建信道Channel後的代碼,在拷貝一份即可


或者可以利用稍微優雅的方式,利用一個實現Runnable的內部類,調用時把連接Connection傳入進去創建信道Channel,這樣有幾個線程就代表一個連接有幾個信道,如下:

public class LogConsumer {

    public static final String EXCHANGE_NAME = "logs";

    private static class ConsumerWorker implements Runnable {

        final Connection connection;

        ConsumerWorker(Connection connection) {
            this.connection = connection;
        }

        @Override
        public void run() {
            try {
                //創建信道
                Channel channel = connection.createChannel();
                //可不創建,由生產者進行創建
                channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

                //聲明一個隨機隊列
                String queueName = channel.queueDeclare().getQueue();

                //將隊列和交換器通過路由鍵進行綁定
                channel.queueBind(queueName, EXCHANGE_NAME, "error");
                channel.queueBind(queueName, EXCHANGE_NAME, "warn");
                channel.queueBind(queueName, EXCHANGE_NAME, "info");

                //聲明瞭一個消費者
                Consumer consumer = new DefaultConsumer(channel) {
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                        StringBuffer buffer = new StringBuffer();
                        buffer.append(Thread.currentThread().getName()).append(", ")
                                .append(envelope.getExchange()).append(", ")
                                .append(envelope.getRoutingKey()).append(", ")
                                .append(new String(body, "UTF-8"));
                        System.out.println(buffer.toString());
                    }
                };
                //消費者正式開始在指定隊列上消費消息
                channel.basicConsume(queueName, true, consumer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        //創建連接,連接到RabbitMQ,與發送端一樣
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        Connection connection = connectionFactory.newConnection();

        //一個連接多個信道
        for (int i = 0; i < 2; i++) {
            //將連接作爲參數,傳遞給每個線程
            Thread worker = new Thread(new ConsumerWorker(connection));
            worker.start();
        }
    }
}

上述我們信道中的隊列名不能重複了,我們可以傳入不同的隊列名稱進去,或者使用channel.queueDeclare().getQueue()去獲取不同的隨機隊列。


另外由於在多線程的情況下,我們像之前一樣分開打印可能會比較錯亂,這裏我們將其拼接在一起進行輸出,並且我們將其線程的名稱也打印了出來,這樣更加能幫助我們理解。


其消息的生成者和RabbitMQ的基礎使用 —— Direct模式(一)中的一致,這裏就不贅述了,直接進行測試,結果如下:
在這裏插入圖片描述




AMQP及RabbitMQ概論中不僅說到一個連接有多個信道,還說過一個隊列可以有多個消費者。


這裏如果想讓一個隊列有多個消費者,我們只需將上述代碼進行修改即可,上述代碼使用了隨機隊列,這裏我們就將其修改爲傳入一個固定的隊列,然後每個線程都會消費這一個隊列,如下:

public class LogConsumer {

    public static final String EXCHANGE_NAME = "logs";

    private static class ConsumerWorker implements Runnable {

        final Connection connection;
        final String queueName;

        public ConsumerWorker(Connection connection,String queueName) {
            this.connection = connection;
            this.queueName = queueName;
        }

        @Override
        public void run() {
            try {
                //創建信道
                Channel channel = connection.createChannel();
                //可不創建,由生產者進行創建
                channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

                //創建一個隊列
                channel.queueDeclare(queueName, false, false, false, null);

                //將隊列和交換器通過路由鍵進行綁定
                channel.queueBind(queueName, EXCHANGE_NAME, "error");
                channel.queueBind(queueName, EXCHANGE_NAME, "warn");
                channel.queueBind(queueName, EXCHANGE_NAME, "info");

                //聲明瞭一個消費者
                Consumer consumer = new DefaultConsumer(channel) {
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                        StringBuffer buffer = new StringBuffer();
                        buffer.append(Thread.currentThread().getName()).append(", ")
                                .append(envelope.getExchange()).append(", ")
                                .append(envelope.getRoutingKey()).append(", ")
                                .append(new String(body, "UTF-8"));
                        System.out.println(buffer.toString());
                    }
                };
                //消費者正式開始在指定隊列上消費消息
                channel.basicConsume(queueName, true, consumer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        //創建連接,連接到RabbitMQ,與發送端一樣
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        Connection connection = connectionFactory.newConnection();

        //一個隊列多個消費者
        String queueName = "allLog";
        for (int i = 0; i < 2; i++) {
            //將連接作爲參數,傳遞給每個線程
            Thread worker = new Thread(new ConsumerWorker(connection, queueName));
            worker.start();
        }
    }
}

這裏消息的生產者還是和之前一樣,無需進行修改,所以我們直接進行測試,測試結果如下:
在這裏插入圖片描述

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