RabbitMQ在Java中的應用(一)

大家學習Java時,都是從打印一條Hello World開始的,同樣,作爲今天學習RabbitMQ的第一課,就使用RabbitMQ接收並轉發一條內容爲 ‘Hello World’ 的消息開始。

介紹

RabbitMQ作爲一個消息中間件,主要用於接收和轉發消息。你可以把它想像成一個郵局,當你往郵局投遞信件時,只要寫上郵寄的地址,就可以確保這個信件會準確的發送過去。RabbitMQ與郵局的唯一區別是它處理的不是紙質的信件而是二進制類型的數據。

下面有幾個核心的專業名詞需要介紹下

  • Producing 它的意思就是消息的生產者。發送消息的程序就可稱爲Producing

Alt

  • Queue 顧名思義,它是一個隊列,類似於RabbitMQ內部的郵箱。消息在RabbitMQ中只能存儲在Queue中。本質上是一個大的消息緩衝區,大小受內存和硬盤的限制。多個Producers可以往Queue中發送消息,多個Consumers可以從Queue獲取消息
    Alt
  • Consuming 它就是信息的接收者,在編程中Consumer大多是等待信息接收
    Alt
    注意:Producer,Consumer,RabbitMQ Server它們沒必要在同一個host下,可以部署到不同的host中。一個程序可以即是Producer又是 Consumer

第一個程序(Hello World)

前提條件:需要安裝RabbitMQ並在本地運行

在這個例子中,我們需要編寫兩個類,一個作爲Producer發送消息,一個作爲Consumer接收並打印消息。
下圖中的P就是Producer,C就是Consumer,中間的紅色方框就是Queue,作爲一個隊列,是RabbitMQ的消息緩衝區
Alt
maven依賴

        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.7.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>

Producer

        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        try (
                Connection connection = connectionFactory.newConnection();
                Channel channel = connection.createChannel();
        ) {
            

        } catch (Exception e) {
            System.out.println("發送數據失敗:" + e.getMessage());
        }

如上面的代碼所示,Connection是對socket連接的抽象,併爲我們處理了協議版本協商和認證的一些低層工作。由於這次的demo是連接到本地環境,所以host設置爲localhost,如果要連接到其它的地址,只需要改成IP或域名即可。然後使用connection對象創建channel對象,程序與RabbitMQ交互都是通過channel對象。
由於Connection、Channel都實現了java.io.Closeable接口,所以將創建connection和channel對象的語句使用try-with-resource方式來寫,這樣就不需要在代碼的關閉資源。

            channel.queueDeclare(Constant.QUEUE_NAME, false, false, false, null);
            for (int i = 0; i < 100; i++) {
                String message = "Hello World! index:" + i;
                channel.basicPublish("", Constant.QUEUE_NAME, null, message.getBytes());
                System.out.println(" Sent '" + message + "'");
            }

如上代碼所示,通過調用channel的queueDeclare方法來創建一個queue,第一個參數是指定queue的名字。如果這個queue不存在,則創建指定name的queue,如果已存在,則不作操作。

Consumer

        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(Constant.QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages.");
        DeliverCallback deliverCallback = (consumeTag,delivery)->{
            String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
            System.out.println(" Received '" + message + "'");
        };
        channel.basicConsume(Constant.QUEUE_NAME, deliverCallback, consumeTag -> {
        });

如上代碼所示,可以看到Consumer的代碼和Producer的代碼很相似。這段代碼有如下幾點注意的地方:

  1. Connection和Channel對象的創建沒有用try-with-resource的方式,因爲需要與RabbitMQg一直保持連接
  2. 這裏也調用了channel的queueDeclare方法,因爲在啓動Consumer時不確定Producer是否已經啓動。通過調用queueDeclare方法可以確保在啓動Consumer時,queue總是存在的

分別啓動Producer和Consumer即可看到效果

源碼地址 https://github.com/qasrc/rabbitmq_tutorials.git

參考文檔 https://www.rabbitmq.com/tutorials/tutorial-one-java.html

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