一、概念
- 發布者/訂閱者模型支持向一個特定的消息主題發布消息。0或多個訂閱者可能對接收來自特定消息主題的消息感興趣。在這種模型下,發布者和訂閱者彼此不知道對方。這種模式好比是匿名公告板。這種模式被概括為:多個消費者可以獲得消息
- 在發布者和訂閱者之間存在時間依賴性。發布者需要建立一個訂閱(subscription),以便客戶能夠訂閱。訂閱者必須保持持續的活動狀態以接收消息,除非訂閱者建立了持久的訂閱。在那種情況下,在訂閱者未連接時發布的消息將在訂閱者重新連接時重新發布。
二、案例
2.1 消息生產者-消息發布者
package com.shyroke.firstActiveMQ2; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; /** * 消息生產者 * @author Administrator * */ public class JMSProducer { private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名 private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼 private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址 private static final int SENDNUM=10; // 發送的消息數量 public static void main(String[] args) { ConnectionFactory connectionFactory; // 連接工廠 Connection connection = null; // 連接 Session session; // 會話 接受或者發送消息的線程 Destination destination; // 消息的目的地 MessageProducer messageProducer; // 消息生產者 // 實例化連接工廠 connectionFactory=new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL); try { connection=connectionFactory.createConnection(); // 通過連接工廠獲取連接 connection.start(); // 啟動連接 session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE); // 創建Session // destination=session.createQueue("FirstQueue1"); // 創建消息隊列 destination=session.createTopic("firstTopic"); messageProducer=session.createProducer(destination); // 創建消息生產者 sendMessage(session, messageProducer); // 發送消息 session.commit(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ if(connection!=null){ try { connection.close(); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 發送消息 * @param session * @param messageProducer * @throws Exception */ public static void sendMessage(Session session,MessageProducer messageProducer)throws Exception{ for(int i=0;i<JMSProducer.SENDNUM;i++){ TextMessage message=session.createTextMessage("ActiveMQ 發布的消息"+i); System.out.println("發送消息:"+"ActiveMQ 發布的消息"+i); messageProducer.send(message); } } }
2.2 消息消費者-消息訂閱者一
package com.shyroke.firstActiveMQ2; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; public class JMSConsumer { private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名 private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼 private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址 public static void main(String[] args) { ConnectionFactory connectionFactory; // 連接工廠 Connection connection = null; // 連接 Session session; // 會話 接受或者發送消息的線程 Destination destination; // 消息的目的地 MessageConsumer consumer; //創建消費者 // 實例化連接工廠 connectionFactory=new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL); try { connection=connectionFactory.createConnection(); // 通過連接工廠獲取連接 connection.start(); // 啟動連接 /** * 這里的最好使用Boolean.FALSE,如果是用true則必須commit才能生效,且http://127.0.0.1:8161/admin管理頁面才會更新消息隊列的變化情況。 */ session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 創建Session // destination=session.createQueue("FirstQueue1"); // 創建消息隊列 destination=session.createTopic("firstTopic"); consumer=session.createConsumer(destination); consumer.setMessageListener(new MyListener()); // 注冊消息監聽 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
監聽器1
package com.shyroke.firstActiveMQ2; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class MyListener implements MessageListener { public void onMessage(Message message) { try { System.out.println("訂閱者一收到的消息:"+((TextMessage)message).getText()); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
2.3 消息消費者-消息訂閱者二
package com.shyroke.firstActiveMQ2; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnection; import org.apache.activemq.ActiveMQConnectionFactory; public class JMSConsumer2 { private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名 private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼 private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址 public static void main(String[] args) { ConnectionFactory connectionFactory; // 連接工廠 Connection connection = null; // 連接 Session session; // 會話 接受或者發送消息的線程 Destination destination; // 消息的目的地 MessageConsumer consumer; //創建消費者 // 實例化連接工廠 connectionFactory=new ActiveMQConnectionFactory(JMSConsumer2.USERNAME, JMSConsumer2.PASSWORD, JMSConsumer2.BROKEURL); try { connection=connectionFactory.createConnection(); // 通過連接工廠獲取連接 connection.start(); // 啟動連接 /** * 這里的最好使用Boolean.FALSE,如果是用true則必須commit才能生效,且http://127.0.0.1:8161/admin管理頁面才會更新消息隊列的變化情況。 */ session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 創建Session // destination=session.createQueue("FirstQueue1"); // 創建消息隊列 destination=session.createTopic("firstTopic"); consumer=session.createConsumer(destination); consumer.setMessageListener(new MyListener2()); // 注冊消息監聽 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
監聽器2
package com.shyroke.firstActiveMQ2; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class MyListener implements MessageListener { public void onMessage(Message message) { try { System.out.println("訂閱者一收到的消息:"+((TextMessage)message).getText()); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
測試以及結果
發布- 訂閱消息模式首先必須訂閱者先訂閱服務,然后發布者再發布消息,最后訂閱者受到服務消息。
所以本章我們先執行消息訂閱者一和消息訂閱者二的代碼然后查看ActiveMQ的管理界面:
如圖可見,訂閱者已經注冊成功,然后再發布者發布消息: