ActiveMQ學習1-JMS和ActiveMQ的兩種發送和接收示例


  

1 Java消息服務和JMS概述

  兩個系統之間或者分佈式系統之間的信息通信,是我們開發中比較常見的場景,比如系統A要把信息發送給系統B,這個問題我們應該如何去處理?
  1999年,原來的SUN公司領銜提出了一種面向消息的中間件服務–JMS規範(標準);
  JMS即Java消息服務(Java Message Service的簡稱),是Java EE 的標準/規範之一。這種規範(標準)指出:消息的發送應該是異步的、非阻塞的。也就是說消息的發送者發送完消息後就直接返回了,不需要等待接收者接收到消息後才能返回,發送者和接收者可以說是互不影響。所以這種規範(標準)能夠減輕或消除系統瓶頸,實現系統之間去除耦合,提高系統的整體可伸縮性和靈活性。
  JMS是Java EE中定義的一組標準API,它自身並不是一個消息服務系統,它是消息傳送服務的一個抽象,也就是說它定義了消息傳送的接口而並沒有具體實現。

2 JMS的發展歷程

JavaEE JMS版本
Java EE 8 Java Message Service API 2.1
Java EE 7 Java Message Service API 2.0
Java EE 6 Java Message Service API 1.1
Java EE 5 Java Message Service API 1.1
J2EE1.4 Java Message Service API 1.1
J2EE1.3 Java Message Service API 1.0 (不成熟,不夠完善)

3 ActiveMQ概述

  ActiveMQ是Apache下的一個項目,採用Java語言開發;ActiveMQ 是一款非常流行的開源消息服務器,實現了JMS規範;官網: http://activemq.apache.org/

4 ActiveMQ環境搭建

4.1 Linux下環境搭建

ActiveMQ運行需要Java的支持,首先需要配置Java環境變量;
1、下載ActiveMQ
2、解壓:其中 -C /usr/local/ 指定把文件解壓到哪裏去

tar -zxvf apache-activemq-5.15.7-bin.tar.gz -C /usr/local/ 

解壓後就安裝完成了,即可使用,不需要其他操作

Java開發的服務器,都是直接解壓即可使用:tomcat、maven、zookeeper、ActiveMQ、Mycat

3、切換到解壓後的activemq的bin目錄下

cd /usr/local/apache-activemq-5.15.7 去啓動

4、切換到bin目錄下,

啓動:./activemq start

5、切換到bin目錄下,

關閉:./activemq stop
無法關閉的問題:
1 把data目錄下的所有文件及目錄都刪除
2 把activeMQ主目錄下的 tmp 目錄也刪除

啓動後有兩個端口號,一個是web控制檯:8161,一個是消息服務broker連接端口:61616
web管理控制檯admin URL地址:http://localhost:8161 默認登錄賬號 admin 密碼 admin,注意:Linux防火前要關閉
消息服務broker URL地址 :

tcp://localhost:61616

4.2 windows下環境搭建

1、下載activeMQ windows版本的壓縮包
2、解壓下載下來的壓縮包,解壓後就可以直接使用
3、進入解壓後的目錄的bin下面
4、在地址欄輸入 cmd 後確定
5、在dos窗口裏面輸入: activemq start 進行啓動
6、關閉:activemq stop 或者Ctrl + c

5 Java消息服務JMS整體設計結構

基本要素:

1、生產者producer
2、消費者consumer
3、消息服務broker

交互模型
在這裏插入圖片描述
JMS兩種消息傳送模式:
1、點對點( Point-to-Point):專門用於使用隊列Queue傳送消息;
2、發佈/訂閱(Publish/Subscribe):專門用於使用主題Topic傳送消息。

  基於隊列Queue的點對點消息只能被一個消費者消費,如多個消費者都註冊到同一個消息隊列上,當生產者發送一條消息後,而只有其中一個消費者會接收到該消息,而不是所有消費者都能接收到該消息。 (1 對 1)
  基於主題的發佈與訂閱消息能被多個消費者消費,生產者發送的消息,所有訂閱了該topic的消費者都能接收到。(1 對 多)

6 Java消息服務JMS API總體概覽

JMS API可以分爲3個主要部分:
1、公共API:可用於向一個隊列或主題發送消息或從其中接收消息;
2、點對點API:專門用於使用隊列Queue傳送消息;
3、發佈/訂閱API:專門用於使用主題Topic傳送消息。

1、JMS公共API
在JMS公共API內部,和發送與接收消息有關的JMS API接口主要是:

ConnectionFactory
Connection
Session
Message
Destination
MessageProducer
MessageConsumer

它們的關係是:一旦有了ConnectionFactory,就可以創建Connection,一旦有了Connection,就可以創建Session,而一旦有了Session,就可以創建Message、MessageProducer和MessageConsumer。

2、JMS點對點API
點對點(p2p)消息傳送模型API是指JMS API之內基於隊列(Queue)的接口:

QueueConnectionFactory
QueueConnection
QueueSession
Message
Queue
QueueSender
QueueReceiver

  從接口的命名可以看出,大多數接口名稱僅僅是在公共API接口名稱之前添加Queue一詞。一般來說,使用點對點消息傳送模型的應用程序將使用基於隊列的API,而不使用公共API 。

3、JMS發佈/訂閱API
發佈/訂閱消息傳送模型API是指JMS API之內基於主題(Topic)的接口:

TopicConnectionFactory
TopicConnection
TopicSession
Message
Topic
TopicPublisher
TopicSubscriber

由於基於主題(Topic)的JMS API類似於基於隊列(Queue)的API,因此在大多數情況下,Queue這個詞會由Topic取代。

7 ActiveMQ點對點發送與接收消息示例

在這裏插入圖片描述

1、加入jms 和 activemq 的相關依賴
2、參考樣例代碼編寫一個消費發送者 和 一個消息接收者
3、運行發送者和接收者的代碼,在activeMQ的web控制檯觀察消息數據
<dependencies>
        <!-- JMS規範的jar依賴 -->
        <dependency>
            <groupId>javax.jms</groupId>
            <artifactId>javax.jms-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- activeMQ對jms具體實現的jar依賴 -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-client</artifactId>
            <version>5.15.8</version>
        </dependency>

        <!--slf4j日誌的簡易實現-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
</dependencies>
public class QueueSender {
    public static final String BROKER_URL = "tcp://localhost:61616";
    public static final String DESTINATION = "myQueue";

    public static void main(String[] args) {
        //1、創建連接工廠
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);

        Connection connection = null;
        Session session = null;
        MessageProducer producer = null;
        try {
            //2、創建一個連接
            connection = connectionFactory.createConnection();

            //3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

            //4、創建消息
            Message message = session.createTextMessage("Hello,ActiveMQ");

            //5、消息目的地
            Destination destination = session.createQueue(DESTINATION);

            //6、消息生產者
            producer = session.createProducer(destination);

            //7、發送消息
            producer.send(message);

        } catch (Exception e) {

        } finally {
            if (producer != null) {
                try {
                    producer.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            //連接的關閉
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在這裏插入圖片描述

public class QueueReceiver {
    public static final String BROKER_URL = "tcp://localhost:61616";
    public static final String DESTINATION = "myQueue";

    public static void main(String[] args) {
        //1、創建連接工廠
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);

        Connection connection = null;
        Session session = null;
        MessageConsumer messageConsumer = null;
        try {
            //2、創建一個連接
            connection = connectionFactory.createConnection();
            //接收消息多一個步驟:把連接啓動
            connection.start();

            //3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

            //4、創建消息
            Message message = session.createTextMessage("Hello,ActiveMQ");

            //5、消息目的地
            Destination destination = session.createQueue(DESTINATION);

            //6、消息消費者
            messageConsumer = session.createConsumer(destination);

            //7、接收消息:receive方法是一個阻塞方法,它會一直等待,直到接收到消息
            //   receive(Long 超時毫秒數) receiveNoWait()不等待
            Message receiveMessage = messageConsumer.receive();

            if (receiveMessage instanceof TextMessage) {
                String text = ((TextMessage) message).getText();
                System.out.println("接收到的消息爲:" + text);
            }

        } catch (Exception e) {

        } finally {
            if ( messageConsumer!= null) {
                try {
                    messageConsumer.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            //連接的關閉
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
接收到的消息爲:Hello,ActiveMQ

Process finished with exit code 0

在這裏插入圖片描述

8 ActiveMQ發佈與訂閱示例

public class TopicPublisher {
    public static final String BROKER_URL = "tcp://localhost:61616";
    public static final String DESTINATION = "myTopic";

    public static void main(String[] args) {
        //1、創建連接工廠
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);

        Connection connection = null;
        Session session = null;
        MessageProducer producer = null;
        try {
            //2、創建一個連接
            connection = connectionFactory.createConnection();

            //3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

            //4、創建消息
            Message message = session.createTextMessage("Hello,ActiveMQ");

            //5、消息目的地
            Destination destination = session.createTopic(DESTINATION);

            //6、消息生產者
            producer = session.createProducer(destination);

            //7、發送消息
            producer.send(message);

        } catch (Exception e) {

        } finally {
            if (producer != null) {
                try {
                    producer.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            //連接的關閉
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class TopicSubscriber {
    public static final String BROKER_URL = "tcp://localhost:61616";
    public static final String DESTINATION = "myTopic";

    public static void main(String[] args) {
        //1、創建連接工廠
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);

        Connection connection = null;
        Session session = null;
        MessageConsumer messageConsumer = null;
        try {
            //2、創建一個連接
            connection = connectionFactory.createConnection();
            //接收消息多一個步驟:把連接啓動
            connection.start();

            //3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

            //4、創建消息
            Message message = session.createTextMessage("Hello,ActiveMQ");

            //5、消息目的地
            Destination destination = session.createTopic(DESTINATION);

            //6、消息消費者
            messageConsumer = session.createConsumer(destination);

            //7、接收消息:receive方法是一個阻塞方法,它會一直等待,直到接收到消息
            //   receive(Long 超時毫秒數) receiveNoWait()不等待
            while (true) {
                Message receiveMessage = messageConsumer.receive();

                if (receiveMessage instanceof TextMessage) {
                    String text = ((TextMessage) message).getText();
                    //可以進行業務邏輯的處理
                    System.out.println("接收到的消息爲:" + text);
                }
            }


        } catch (Exception e) {

        } finally {
            if ( messageConsumer!= null) {
                try {
                    messageConsumer.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            //連接的關閉
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
注意:
發佈訂閱模式必須先啓動訂閱者,再啓動發佈者,否則消息接收不到

9 Queue與Topic比較

在這裏插入圖片描述

Queue模式,如果消息沒有接收,消息存放在服務器,重啓後消息還在。
Topic模式,沒有被接收的消息,重啓服務器後,消息就不存在。

10 拉模式與推模式

  點對點消息,如果沒有消費者在監聽隊列,消息將保留在隊列中,直至消息消費者連接到隊列爲止。在這種模型中,消息不是自動推動給消息消費者的,而是要由消息消費者從隊列中請求獲得 (拉模式)。
  pub/sub消息傳遞模型基本上是一個推模型。在該模型中,消息會自動廣播,消息消費者無須通過主動請求或輪詢主題的方法來獲得新的消息。

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