點對點的消息傳遞中,目的地被稱爲隊列(Queue)
點對點消息傳遞的特點如下:
(1)每個消息只能有一個消費者,類似 1 對 1 的關係,好比個人快遞自己領取自己的
(2)消息的生產者和消費者之間 沒有時間上的相關性。無論消費者在生產者發送消息的時候是否處於運行狀態,消費者都可以提取消息。好比我們的發送短信,發送者發送後不見得接收者會立即收看
(3)消息被消費後隊列中 不會再存儲,所以消費者 不會消費到已經被消費掉的消息
創建 Maven 工程
關於怎麼創建 Maven 工程這裏就不詳細講解了,不會的朋友網上找一下
添加相關依賴
<!-- activemq 所需要的 jar 包配置 -->
org.apache.activemq
activemq-all
5.15.9
org.apache.xbean
xbean-spring
3.16
消息生產者
package com.java.elasticsearch.activemq;
import org.apache.activemq.ActiveMQConnectionFactory;import javax.jms.*;/**
* @author Woo_home
* @create by 2020/5/221:32
*/
public class JmsProduce {
// 定義 MQ 連接地址
private static final String ACTIVE_MQ_URL = "tcp://localhost:61616";
// 定義隊列名稱
private static final String QUEUE_NAME = "queue01";
public static void main(String[] args) throws JMSException {
// 創建連接工廠
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
// 通過連接工廠,獲得連接 Connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
// 創建會話
// 兩個參數,第一個叫事務 /第二個叫簽收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//創建目的地(具體是隊列還是主題 Topic)
Queue queue = session.createQueue(QUEUE_NAME);//創建消息的生產者
MessageProducer messageProducer = session.createProducer(queue);//通過使用 MessageProducer 生產3條消息發送到 MQ 的隊列裏面
for(int i =0; i <3; i++) {
//創建消息
TextMessage textMessage = session.createTextMessage ("msg---"+ i);//理解爲一個字符串
// 通過 MessageProducer 發送給 MQ
messageProducer.send (textMessage);
}
// 關閉資源
messageProducer.close();
session.close();
connection.close();
System.out.println("****** 消息發佈到 MQ 完成 ******");
}
}
在運行該程序之前我們需要先啓動一下 ActiveMQ
訪問 http://localhost:8161/admin/,點擊 Queues 選項
隊列中也是啥也沒有
然後我們運行一下上面的程序
控制檯已顯示成功將消息發送到 MQ 了 http://localhost:8161/admin/queues.jsp
然後我們再次刷新 Queues 界面,已經接收到了 3 條消息
通過該界面不難發現,我們在代碼中定義了一個隊列名稱爲 queue01,該界面顯示的隊列名稱就是我們手動設置的
Queues 說明:
總結
當有一個消息進入這個隊列時,等待消費的消息是 1,進入隊列的消息是 1
當消息消費後,等待消費的消息是 0,進入隊列的消息是 1,出隊列的消息是 1
再來一條消息時,等待消費的消息是 1,進入隊列的消息就是 2
消息消費者
package com.java.elasticsearch.activemq;
import org.apache.activemq.ActiveMQConnectionFactory;import javax.jms.*;/**
* @author Woo_home
* @create by 2020/5/30:51
*/
public class JmsConsumer {
// 定義 MQ 連接地址
private static final String ACTIVE_MQ_URL = "tcp://localhost:61616";
// 定義隊列名稱
private static final String QUEUE_NAME = "queue01";
public static void main (String[] args) throws JMSException {
// 1、創建連接工廠
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
// 2、通過連接工廠,獲得連接 Connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
///3、創建會話
// 兩個參數,第一個叫事務 /第二個叫簽收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4、創建目的地(具體是隊列還是主題 Topic)
Queue queue = session.createQueue(QUEUE_NAME);//5、創建消費者
MessageConsumer messageConsumer = session.createConsumer(queue);while(true) {
//同步阻塞方式(receive)
// 因爲消息生產者是 TextMessage,所以這裏需要轉換一下
TextMessage textMessage = (TextMessage) messageConsumer.receive();
if (null != textMessage) {
System.out.println ("****** 消費者接收到消息 ******:" + textMessage.getText());
} else {
break;
}
}
// 關閉資源
messageConsumer.close();
session.close();
connection.close();
}
}
在運行消費端代碼之前,再觀察一下該界面 http://localhost:8161/admin/queues.jsp
此時有 3 條消息等待被消費,然後我們運行一下消費端代碼
控制檯輸出,消費端已經接收到生產者的消息
然後再看下 Queues 界面 http://localhost:8161/admin/queues.jsp
此時消息已經出現 3 條,有一個消費者
消息消費者 receive() 方法說明
在上面的代碼中有一個 receive 方法,會一直在等待
在 Queues 界面中也會顯示有一個客戶一直在消費
這是因爲 receive 默認是一直等待的,還有一個 receive(timeout) 是可以設置時間的
如下:
// 只會等待 4 s
TextMessage textMessage = (TextMessage) messageConsumer.receive(4000L);
消息消費者 MessageListener 方法說明
package com.java.elasticsearch.activemq;
import org.apache.activemq.ActiveMQConnectionFactory;import javax.jms.*;import java.io.IOException;/**
* @author Woo_home
* @create by 2020/5/30:51
*/
public class JmsConsumer {
// 定義 MQ 連接地址
private static final String ACTIVE_MQ_URL = "tcp://localhost:61616";
// 定義隊列名稱
private static final String QUEUE_NAME = "queue01";
public static void main(String[] args) throws JMSException, IOException {
// 1、創建連接工廠
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
// 2、通過連接工廠,獲得連接 Connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
///3、創建會話
// 兩個參數,第一個叫事務 /第二個叫簽收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4、創建目的地(具體是隊列還是主題 Topic)
Queue queue = session.createQueue(QUEUE_NAME);//5、創建消費者
MessageConsumer messageConsumer = session.createConsumer(queue);//通過監聽的方式來消費消息 MessageConsumer messageConsumer = session.createConsumer(queue)
messageConsumer.setMessageListener (new MessageListener() {@Overridepublic void onMessage (Message message) {if(null != message && message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;try {System.out.println("****** 消費者接收到消息 ****** :"+ textMessage.getText());
} catch (JMSException e) {e.printStackTrace();}}}});System.in.read();
//關閉資源
messageConsumer.close();session.close();connection.close();}}
使用 MessageListener 的作用是有消息就消費,沒消息就等待
總結
兩種消費方式
同步阻塞方式(receive())
訂閱者或者接收者調用 MessageConsumer 的 receive() 方法來接收消息,receive 方法在能夠接收到消息之前(或者超時之前)將一直阻塞
異步非阻塞方式(監聽器 onMessage())
訂閱者或接收者通過 MessageConsumer 的 setMessageListener(MessageListener listener) 註冊一個消息監聽器
當消息到達之後,系統自動調用監聽器 MessageListener 的 onMessage(Message message)