淺談ActiveMQ與使用

蘋果大大個發表於2019-07-20

一、什麼是訊息中介軟體

訊息中介軟體顧名思義實現的就是在兩個系統或兩個客戶端之間進行訊息傳送

二、什麼是ActiveMQ

ActiveMQ是一種開源的基於JMS(Java Message Servie)規範的一種訊息中介軟體的實現,ActiveMQ的設計目標是提供標準的,面向訊息的,能夠跨越多語言和多系統的應用整合訊息通訊中介軟體。

三、什麼時候需要用ActiveMQ

ActiveMQ常被應用與系統業務的解耦,非同步訊息的推送,增加系統併發量,提高使用者體驗。例如以我在工作中的使用,在比較耗時且非同步的遠端開鎖操作時

四、如何使用ActiveMQ

1.AcitveMQ的資料傳送流程

2.ActiveMQ的兩種訊息傳遞型別

(1)點對點傳輸,即一個生產者對應一個消費者,生產者向broke推送資料,資料儲存在broke的一個佇列中,當消費者接受該條佇列裡的資料。

(2)基於釋出/訂閱模式的傳輸,即根據訂閱話題來接收相應資料,一個生產者可向多個消費者推送資料,與MQTT協議的實現是類似的,對MQTT協議有興趣的可跳轉到https://www.cnblogs.com/xiguadadage/p/11216463.html

兩種訊息傳遞型別的不同,點對點傳輸消費者可以接收到在連線之前生產者所推送的資料,而基於釋出/訂閱模式的傳輸方式消費者只能接收到連線之後生產者推送的資料。

3.ActiveMQ的安裝與啟動

(1)官網下載對應伺服器版本

(2)解壓後進入apache-activemq-5.15.9/bin目錄

(3)執行./activemq start啟動ActiveMQ

(4)瀏覽器輸入ActiveMQ啟動的伺服器ip:8161便可進入web介面,點選Manage ActiveMQ broker可以檢視訊息推送的狀態,預設賬號密碼為admin,admin

(5)啟動錯誤分析

進入/root/apache-activemq-5.15.9/data目錄檢視activemq.log檔案,根據錯誤提示資訊修改,例如埠號被佔用等。

4.ActiveMQ的程式碼測試

(1)構建maven專案,引入依賴

<dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-all</artifactId>
            <version>5.9.0</version>
        </dependency>

(2)生產者類

/**
 * @Description 生產者
 * @Date 2019/7/20
 * @Created by yqh
 */
public class MyProducer {

    private static final String ACTIVEMQ_URL = "tcp://192.168.168.242:61616";

    public static void main(String[] args) throws JMSException {
        // 建立連線工廠
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        // 建立連線
        Connection connection = activeMQConnectionFactory.createConnection();
        // 開啟連線
        connection.start();
        // 建立會話
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // 建立佇列目標,並標識佇列名稱,消費者根據佇列名稱接收資料
        Destination destination = session.createQueue("myQueue");
        // 建立一個生產者
        MessageProducer producer = session.createProducer(destination);
        // 向佇列推送10個文字訊息資料
        for (int i = 1 ; i <= 10 ; i++){
            // 建立文字訊息
            TextMessage message = session.createTextMessage("第" + i + "個文字訊息");
            //傳送訊息
            producer.send(message);
            //在本地列印訊息
            System.out.println("已傳送的訊息:" + message.getText());
        }
        //關閉連線
        connection.close();
    }

}

執行結果:

已傳送的訊息:第1個文字訊息
已傳送的訊息:第2個文字訊息
已傳送的訊息:第3個文字訊息
已傳送的訊息:第4個文字訊息
已傳送的訊息:第5個文字訊息
已傳送的訊息:第6個文字訊息
已傳送的訊息:第7個文字訊息
已傳送的訊息:第8個文字訊息
已傳送的訊息:第9個文字訊息
已傳送的訊息:第10個文字訊息

測試檢視web後臺顯示,有10條訊息在佇列中等待消費

(3)消費者類

/**
 * @Description 消費者類
 * @Date 2019/7/20 0020
 * @Created by yqh
 */
public class MyConsumer {

    private static final String ACTIVEMQ_URL = "tcp://192.168.168.242:61616";

    public static void main(String[] args) throws JMSException {
        // 建立連線工廠
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        // 建立連線
        Connection connection = activeMQConnectionFactory.createConnection();
        // 開啟連線
        connection.start();
        // 建立會話
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // 建立佇列目標,並標識佇列名稱,消費者根據佇列名稱接收資料
        Destination destination = session.createQueue("myQueue");
        // 建立消費者
        MessageConsumer consumer = session.createConsumer(destination);
        // 建立消費的監聽
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                TextMessage textMessage = (TextMessage) message;
                try {
                    System.out.println("消費的訊息:" + textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

測試結果:

消費的訊息:第1個文字訊息
消費的訊息:第2個文字訊息
消費的訊息:第3個文字訊息
消費的訊息:第4個文字訊息
消費的訊息:第5個文字訊息
消費的訊息:第6個文字訊息
消費的訊息:第7個文字訊息
消費的訊息:第8個文字訊息
消費的訊息:第9個文字訊息
消費的訊息:第10個文字訊息

web後臺顯示有一個消費者處於連線狀態,且已消費了10個message,而該條佇列已沒有message待消費了

(4)當我們執行兩個消費者類,訊息又是怎麼被消費的呢?是兩個消費者都能收到生產者生產的message,還是隻有其中一個消費者能消費呢?

我們先執行兩個消費者,在執行一個生產者對目標佇列生產10個message,會發現有以下情況

// Consumer1控制檯
消費的訊息:第1個文字訊息
消費的訊息:第3個文字訊息
消費的訊息:第5個文字訊息
消費的訊息:第7個文字訊息
消費的訊息:第9個文字訊息
// Consumer2控制檯
消費的訊息:第2個文字訊息
消費的訊息:第4個文字訊息
消費的訊息:第6個文字訊息
消費的訊息:第8個文字訊息
消費的訊息:第10個文字訊息

即佇列中的資料會平均的分給每一個消費者消費,且每一條資料只能被消費一次

(5)以上是基於佇列點對點的傳輸型別,以下是基於釋出/訂閱模式傳輸的型別測試

/**
 * @Description 基於釋出/訂閱模式傳輸型別的生產者測試
 * @Date 2019/7/20 0020
 * @Created by yqh
 */
public class MyProducerForTopic {

    private static final String ACTIVEMQ_URL = "tcp://192.168.168.242:61616";

    public static void main(String[] args) throws JMSException {
        // 建立連線工廠
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        // 建立連線
        Connection connection = activeMQConnectionFactory.createConnection();
        // 開啟連線
        connection.start();
        // 建立會話
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // 建立佇列目標,並標識佇列名稱,消費者根據佇列名稱接收資料
        Destination destination = session.createTopic("topicTest");
        // 建立一個生產者
        MessageProducer producer = session.createProducer(destination);
        // 向佇列推送10個文字訊息資料
        for (int i = 1 ; i <= 10 ; i++){
            // 建立文字訊息
            TextMessage message = session.createTextMessage("第" + i + "個文字訊息");
            //傳送訊息
            producer.send(message);
            //在本地列印訊息
            System.out.println("已傳送的訊息:" + message.getText());
        }
        //關閉連線
        connection.close();
    }

}
/**
 * @Description 基於釋出/訂閱模式傳輸型別的消費者測試
 * @Date 2019/7/20 0020
 * @Created by yqh
 */
public class MyConsumerForTopic {

    private static final String ACTIVEMQ_URL = "tcp://192.168.168.242:61616";

    public static void main(String[] args) throws JMSException {
        // 建立連線工廠
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        // 建立連線
        Connection connection = activeMQConnectionFactory.createConnection();
        // 開啟連線
        connection.start();
        // 建立會話
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // 建立佇列目標,並標識佇列名稱,消費者根據佇列名稱接收資料
        Destination destination = session.createTopic("topicTest");
        // 建立消費者
        MessageConsumer consumer = session.createConsumer(destination);
        // 建立消費的監聽
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                TextMessage textMessage = (TextMessage) message;
                try {
                    System.out.println("消費的訊息:" + textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

現在如果我們先啟動生產者,再啟動消費者,會發現消費者是無法接收到之前生產者之前所生產的資料,只有消費者先啟動,再讓生產者消費才可以正常接收資料,這也是釋出/訂閱的主題模式與點對點的佇列模式的一個明顯區別。

而如果啟動兩個消費者,那麼每一個消費者都能完整的接收到生產者生產的資料,即每一條資料都被消費了兩次,這是釋出/訂閱的主題模式與點對點的佇列模式的另一個明顯區別。

 

 

 

 

相關文章