ActiveMQ是JMS規範的一個實現產品,即對JMS的一套接口進行了實現。所以下面我們先對JMS與ActiveMQ進行一個簡單介紹,然後再介紹ActiveMQ的P2P與PubSub兩種開發模式。
一、 JMS簡介
JMS即Java消息服務,是J2EE的13規範之一,是一套面向消息中間件(MOM)的應用程序接口。用在兩個程序之間,或分佈式系統中發送消息,進行異步通信。
JMS使我們能夠通過消息收發服務(也可以稱爲,消息中介程序或路由器)從一個JMS客戶機向另一個JMS客戶機發送消息。消息是JMS中的一種類型對象,由兩部分組成:報頭和消息主體。報頭由路由信息以及有關該消息的元數據組成。消息主體則攜帶着應用程序的數據或有效負載。根據有效負載的類型來劃分,消息可分爲多種,它們分別攜帶:簡單文本消息、可序列化的對象、屬性集合、字節流、原始值流、無有效負載消息。
二、 ActiveMQ簡介
ActiveMQ出身名門,是Apache門下的最流行的,能力強勁的開源消息總線。完全支持JMS1.1和J2EE1.4規範的JMS Provide實現。它從設計上保證了高性能的集羣,當然實現了JMS的P2P與PubSub兩種開發模式。
三、 安裝運行ActiveMQ
首先下載ActiveMQ的穩定版:http://activemq.apache.org ,如下圖,我下載的是apache-activemq-5.11.1-bin:
然後進入到bin/win64文件夾下,並啓動activemq.bat:
出現如下提示表示ActiveMQ啓動成功:
然後在瀏覽器輸入:http://localhost:8161/即可看到ActiveMQ的管理界面:
然後我們點擊:Manage ActiveMQ broker登錄管理後臺:(用戶名、密碼默認都爲admin)
登錄進去以後我們可以點擊Queues看到消息隊列以及消費者情況等:
四、 P2P開發模式實戰
建立JavaProject:ActiveMQ-p2p,並導入ActiveMQ的核心jar包,只需要導入根目錄下的activemq-all.jar即可:
然後建立一個消息生產者類:JMSProducer;一個消息消費者類:JMSConsumer:
源碼如下:
消息生產者類:JMSProducer
package com.tgb.jms.ActiveMQ;
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"); // 創建消息隊列
messageProducer = session.createProducer(destination); // 創建消息生產者
sendMessage(session, messageProducer); // 發送消息
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
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);
}
}
}
消息消費者類:JMSConsumer
package com.tgb.jms.ActiveMQ;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息消費者
*
* @author wangzhipeng
*
*/
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 messageConsumer;// 消息消費者
// 實例化連接工廠
connectionFactory = new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL);
try {
connection = connectionFactory.createConnection();// 通過工廠獲取連接
connection.start();// 啓動連接
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 第一個參數爲是否開啓事務
destination = session.createQueue("FirstQueue1");// 創建消息隊列
messageConsumer = session.createConsumer(destination);// 創建消息消費者
/*
* 實際應用中,不會這麼用,會註冊一個監聽
*/
while (true) {
TextMessage textMessage = (TextMessage) messageConsumer.receive(100000);
if (textMessage != null) {
System.out.println("收到的消息:" + textMessage.getText());
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
然後我們運行JMSProducer的main方法來生產10條消息,成功執行後,我們刷新一下後臺頁面,可以看到我們剛纔創建的消息隊列:FirstQueue1,消息個數爲10,沒有消費者,進入隊列的消息爲10,出列消息個數爲0:
然後我們運行JMSConsumer類的main方法,來接收FirstQueue1的消息,成功執行後,我們再刷新後臺頁面,發現消息已被接收:
P2P開發模式優化
上面的實例中我們接收消息的方式爲,寫了一個死循環while (true) 來不停的接收消息,這樣很浪費cpu資源,實際生產中不會這麼做。這裏,我們可以註冊一個監聽器,當監聽到有消息入隊列後,纔去接收消息。所以,改動如下:
首先,新建一個監聽類Listener,需要實現MessageListener接口:
package com.tgb.jms.ActiveMQ2;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
/**
* 消息監聽
*
* @author zhipeng
*
*/
public class Listener implements MessageListener {
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
try {
System.out.println("收到的消息:" + ((TextMessage) message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
然後我們將消息接收者類JMSConsumer的while (true)死循環代碼替換爲messageConsumer.setMessageListener
(newListener());即可,如下圖:
這樣一來我們就符合我們人爲的思維操作了,會節省很多cpu資源。
五、 PubSub開發模式實戰
P2P的模式相當於一個消息生產者一個消費者,PubSub中可以有一個消息發佈者多個消息訂閱者,開發與P2P幾乎一樣,只是將createQueue(創建消息隊列)改爲了createTopic(創建主題);生產消息改爲了發佈消息;接收消息改爲了訂閱消息。代碼這裏就不再貼出來了。有需要的同志到這裏下載http://download.csdn.net/detail/wang379275614/9023177。
這裏需要注意的是,訂閱者必須先訂閱,然後發佈者發送消息後,訂閱者才能自動收到消息。
六、 總結
ActiveMQ是JMS規範的一個實現產品,主要用在兩個程序之間,或分佈式系統中發送消息,進行異步通信。我們可以用它來解決高併發的問題,或者分佈式事務的問題等。