原文鏈接:http://blog.csdn.net/dengwanchuan/article/details/10241345
1.ActiveMQ概述
企業消息軟件從80年代起就存在,它不只是一種應用間消息傳遞風格,也是一種集成風格。因此,消息傳遞可以滿足應用間的通知和互相操作。但是開源的解決方案是到最近10年纔出現的。Apache ActiveMQ就是其中一種。它使應用間能以異步,鬆耦合方式交流。ActiveMQ 是Apache出品,最流行的,能力強勁的開源消息總線。
ActiveMQ是Apache軟件基金下的一個開源軟件,它遵循JMS規範(Java Message Service),是消息驅動中間件軟件(MOM)。它爲企業消息傳遞提供高可用,出色性能,可擴展,穩定和安全保障。ActiveMQ使用Apache許可協議。因此,任何人都可以使用和修改它而不必反饋任何改變。這對於商業上將ActiveMQ用在重要用途的人尤爲關鍵。MOM的工作是在分佈式的各應用之間調度事件和消息,使之到達指定的接收者。所以高可用,高性能,高可擴展性尤爲關鍵。
2.ActiveMQ特性
⒈支持多種語言客戶端,如:Java,C,C++,C#,Ruby,Perl,Python,PHP。應用協議有 OpenWire,Stomp REST,WS Notification,XMPP,AMQP。
⒉ 完全支持JMS1.1和J2EE1.4規範,它們包括同步和異步消息傳遞,一次和只有一次的消息傳遞,對於預訂者的持久消息等等。依附於JMS規範意味着,不論JMS消息提供者是誰,同樣的基本特性(持久化,XA消息,事務)都是有效的。
⒊ 對Spring的支持,ActiveMQ可以很容易內嵌到使用Spring的系統裏面去。
⒋ 通過了常見J2EE服務器(如 Geronimo,JBoss 4,GlassFish,WebLogic)的測試,其中通過JCA 1.5 resource adaptors的配置,可以讓ActiveMQ可以自動的部署到任何兼容J2EE 1.4 商業服務器上。
⒌ ActiveMQ提供各種連接選擇,包括HTTP,HTTPS,IP多點傳送,SSL,STOMP,TCP,UDP,XMPP等。大量的連接協議支持使之具有更好的靈活性。很多現有的系統使用一種特定協議並且不能改變,所以一個支持多種協議的消息平臺降低了使用的門檻。雖然連接很重要,但是和其他容器集成也同樣重要。
6.ActiveMQ提供多種持久性方案可供選擇,也可以完全按自己需求定製驗證和授權。例如,ActiveMQ通過KahaDB提供自己的超快速消息持久方案(ultra-fast message persistence),但也支持標準的JDBC方案。ActiveMQ可以通過配置文件提供簡單的驗證和授權,也提供標準的JAAS登陸模塊。
7.ActiveMQ是爲開發者設計的。它並不需要專門的管理工具,因爲它提供各種易用且強大的管理特性。有很多方法去監控ActiveMQ的各個方面,可以通過JMX使用JConsole或ActiveMQ web console;可以運行ActiveMQ消息報告;可以用命令行腳本;可以通過日誌。
8.代理器集羣(Broker clustering)----爲了利於擴展,多個ActiveMQ broker能夠聯合工作。這個方式就是network of brokers並且能支持多種拓撲結構;支持客戶端-服務器,點對點。
9.支持Ajax, 支持與Axis的整合
3.ActiveMQ優勢
1.與OpenJMS、JbossMQ等開源jms provider相比,ActiveMQ有Apache的支持,持續發展的優勢明顯。
2.速度很快,JBossMQ的十倍(沒有測試)
3.提高系統資源的利用率,主要是任務的派發不是24小時平均的,而是高峯時期任務量很多,比如1秒1000多個,有的時候很低,比如十幾秒鐘纔來一個。應用服務通過JMS隊列一個一個的取任務,做完一個再領一個,使系統資源的運用趨於平均。而JMS,比如JMS接收消息的效率是很高的,比如ActiveMQ,在賽揚(2.40GHz)機器上能夠達到2000/s,消息大小爲1-2k。好一些的服務器可以達到2萬以上/秒。
4.ActiveMQ安裝
首先去http://activemq.apache.org/download.html 下載最新版本ActiveMQ 5.8.0 Release, 解壓apache-activemq-5.8.0-bin.zip(或者apache-activemq-5.8.0-bin.tar.gz)
目錄如下:
+bin (windows下面的bat和unix/linux下面的sh)
+conf (activeMQ配置目錄,包含最基本的activeMQ配置文件)
+data (默認是空的)
+docs (只有index.html)
+example (幾個例子)
+lib (activemMQ使用到的lib)
+webapps(後臺管理頁面)
+webapps-demo(後臺管理消息發送頁面)
+activemq-all-5.8.0.jar (java開發的jar包)
-LICENSE.txt
-NOTICE.txt
-README.txt
-user-guide.html
你可以使用bin\activemq.bat(activemq)啓動。
啓動ActiveMQ以後,登陸:http://localhost:8161/admin/ 默認用戶/密碼爲admin/admin。
注意:
⒈ 這個僅僅是最基礎的ActiveMQ的配置,很多地方都沒有配置因此不要直接使用這個配置用於生存環境。
⒉ 有的時候由於端口被佔用,導致ActiveMQ錯誤,ActiveMQ可能需要以下端口1099(JMX),61616(默認的TransportConnector)。
⒊ 如果沒有物理網卡,或者MS的LoopBackAdpater Multicast會報一個錯誤
5.運行附帶的示例程序
1、Queue消息示例:
* 啓動Queue消息消費者
cd example
ant consumer
* 啓動Queue消息生產者
cd example
ant producer
簡要說明:生產者(producer)發消息,消費者(consumer)接消息,發送/接收2000個消息後自動關閉
2、Topic消息示例:
* 啓動Topic消息消費者
cd example
ant topic-listener
* 啓動Topic消息生產者
cd example
ant topic-publisher
簡要說明:重複10輪,publisher每輪發送2000個消息,並等待獲取listener的處理結果報告,然後進入下一輪 發送,最後
統計全局發送時間。
3、Queue消息和Topic消息發送之後,可以通過後臺點擊Queues和Topics查看發送消息具體信息。
6.ActiveMQ類別及開發流程
1)、Point-to-Point (點對點)消息模式開發流程 :
1、生產者(producer)開發流程(ProducerTool.java):
1.1 創建Connection: 根據url,user和password創建一個jms Connection。
1.2 創建Session: 在connection的基礎上創建一個session,同時設置是否支持事務和ACKNOWLEDGE標識。
1.3 創建Destination對象: 需指定其對應的主題(subject)名稱,producer和consumer將根據subject來發送/接收對應的消息。
1.4 創建MessageProducer: 根據Destination創建MessageProducer對象,同時設置其持久模式。
1.5 發送消息到隊列(Queue): 封裝TextMessage消息,使用MessageProducer的send方法將消息發送出去。
2、消費者(consumer)開發流程(ConsumerTool.java):
2.1 實現MessageListener接口: 消費者類必須實現MessageListener接口,然後在onMessage()方法中監聽消息的到達並處理。
2.2 創建Connection: 根據url,user和password創建一個jms Connection,如果是durable模式,還需要給connection設置一個clientId。
2.3 創建Session和Destination: 與ProducerTool.java中的流程類似,不再贅述。
2.4 創建replyProducer【可選】:可以用來將消息處理結果發送給producer。
2.5 創建MessageConsumer: 根據Destination創建MessageConsumer對象。
2.6 消費message: 在onMessage()方法中接收producer發送過來的消息進行處理,並可以通過replyProducer反饋信息給producer
- if (message.getJMSReplyTo() != null) {
- replyProducer.send(message.getJMSReplyTo(),
- session.createTextMessage("Reply: " + message.getJMSMessageID()));
2)、Publisher/Subscriber(發佈/訂閱者)消息模式開發流程
1、訂閱者(Subscriber)開發流程(TopicListener.java):
1.1 實現MessageListener接口: 在onMessage()方法中監聽發佈者發出的消息隊列,並做相應處理。
1.2 創建Connection: 根據url,user和password創建一個jms Connection。
1.3 創建Session: 在connection的基礎上創建一個session,同時設置是否支持事務和ACKNOWLEDGE標識。
1.4 創建Topic: 創建2個Topic, topictest.messages用於接收發布者發出的消息,topictest.control 用於向發佈者發送消息,實現雙方的交互。
1.5 創建consumer和producer對象:根據topictest.messages創建consumer,根據topictest.control創建 producer。
1.6 接收處理消息:在onMessage()方法中,對收到的消息進行處理,可直接簡單在本地顯示消息,或者根 據消息內容不同處理對應的業務邏輯(比如:數據庫更新、文件操作等等),並且可以使用producer對象將處理結果返回給發佈者。
2、發佈者(Publisher)開發流程(TopicPublisher.java):
2.1 實現MessageListener接口:在onMessage()方法中接收訂閱者的反饋消息。
2.2 創建Connection: 根據url,user和password創建一個jms Connection。
2.3 創建Session: 在connection的基礎上創建一個session,同時設置是否支持事務和ACKNOWLEDGE標識。
2.4 創建Topic: 創建2個Topic,topictest.messages用於向訂閱者發佈消息,topictest.control用於接 收訂閱者反饋的消息。這2個topic與訂閱者開發流程中的topic是一一對應的。
2.5 創建consumer和producer對象: 根據topictest.messages創建publisher; 根據topictest.control 創建consumer,同時監聽訂閱者反饋的消息。
2.6 給所有訂閱者發送消息,並接收反饋消息: 示例代碼中,一共重複10輪操作。 每輪先向所有訂閱者 發送2000個消息; 然後堵塞線程,開始等待; 最後通過onMessage()方法,接收到訂閱者反饋的“REPORT”類信息後,才print反饋信息並解除線程堵塞,進入下一輪。
注:可同時運行多個訂閱者測試查看此模式效果
7.Eclipse代碼開發
1.建立一個Web Probject 項目,將activemq-all-5.8.0.jar放在lib裏面
2.Queue(點對點)方式:生產者
- package jms;
- import javax.jms.Connection;
- import javax.jms.ConnectionFactory;
- import javax.jms.DeliveryMode;
- import javax.jms.Destination;
- import javax.jms.MessageProducer;
- import javax.jms.Queue;
- import javax.jms.Session;
- import javax.jms.TextMessage;
- import org.apache.activemq.ActiveMQConnection;
- import org.apache.activemq.ActiveMQConnectionFactory;
- //Queue(點對點)方式 生存者Producer
- public class QueueProducer {
- private static String user = ActiveMQConnection.DEFAULT_USER;
- private static String password =ActiveMQConnection.DEFAULT_PASSWORD;
- private static String url = "tcp://localhost:61616";
- public static void main(String[] args)throws Exception {
- // ConnectionFactory :連接工廠,JMS 用它創建連接
- ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
- // Connection :JMS 客戶端到JMS Provider 的連接
- Connection connection = connectionFactory.createConnection();
- // Connection 啓動
- connection.start();
- System.out.println("Connection is start...");
- // Session: 一個發送或接收消息的線程
- Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
- // Queue :消息的目的地;消息發送給誰.
- Queue destination = session.createQueue("example.A");
- // MessageProducer:消息發送者
- MessageProducer producer = session.createProducer(destination);
- // 設置不持久化,此處學習,實際根據項目決定
- producer.setDeliveryMode(DeliveryMode.PERSISTENT);
- // 構造消息,此處寫死,項目就是參數,或者方法獲取
- sendMessage(session, producer);
- session.commit();
- connection.close();
- System.out.println("send text ok.");
- }
- public static void sendMessage(Session session, MessageProducer producer)
- throws Exception {
- for (int i = 1; i <= 100; i++) {//有限制,達到1000就不行
- TextMessage message = session.createTextMessage("ActiveMq 發送的消息" + i);
- // 發送消息到目的地方
- System.out.println("發送消息:" + "ActiveMq 發送的消息" + i);
- producer.send(message);
- }
- }
- }
3.Queue(點對點)方式:消費者
- package jms;
- import javax.jms.Connection;
- import javax.jms.ConnectionFactory;
- import javax.jms.Destination;
- import javax.jms.JMSException;
- import javax.jms.Message;
- import javax.jms.MessageConsumer;
- import javax.jms.MessageListener;
- import javax.jms.Queue;
- import javax.jms.Session;
- import javax.jms.TextMessage;
- import org.apache.activemq.ActiveMQConnection;
- import org.apache.activemq.ActiveMQConnectionFactory;
- //Queue(點對點)方式 消費這Consumer
- public class QueueConsumer {
- private static String user = ActiveMQConnection.DEFAULT_USER;
- private static String password =ActiveMQConnection.DEFAULT_PASSWORD;
- private static String url = "tcp://localhost:61616";
- public static void main(String[] args) throws Exception{
- // ConnectionFactory :連接工廠,JMS 用它創建連接
- ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
- // Connection :JMS 客戶端到JMS Provider 的連接
- Connection connection = connectionFactory.createConnection();
- connection.start();
- // Session: 一個發送或接收消息的線程
- final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
- // Destination :消息的目的地;消息發送給誰.
- Queue destination=session.createQueue("example.A");
- // 消費者,消息接收者
- MessageConsumer consumer = session.createConsumer(destination);
- consumer.setMessageListener(new MessageListener(){//有事務限制
- @Override
- public void onMessage(Message message) {
- try {
- TextMessage textMessage=(TextMessage)message;
- System.out.println(textMessage.getText());
- } catch (JMSException e1) {
- e1.printStackTrace();
- }
- try {
- session.commit();
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- });
- /* 另外一種接受方式
- * while (true) {
- //設置接收者接收消息的時間,爲了便於測試,這裏誰定爲100s
- TextMessage message = (TextMessage) consumer.receive(100000);
- if (null != message) {
- System.out.println("收到消息" + message.getText());
- } else {
- break;
- }
- }*/
- }
- }
4.Topic(發佈/訂閱)方式:發佈者
- package jms;
- import java.util.Date;
- import javax.jms.Connection;
- import javax.jms.ConnectionFactory;
- import javax.jms.DeliveryMode;
- import javax.jms.JMSException;
- import javax.jms.MapMessage;
- import javax.jms.MessageProducer;
- import javax.jms.Queue;
- import javax.jms.Session;
- import javax.jms.TextMessage;
- import javax.jms.Topic;
- import org.apache.activemq.ActiveMQConnection;
- import org.apache.activemq.ActiveMQConnectionFactory;
- //Topic(發佈/訂閱)方式 發佈者Publisher
- public class TopicPublisher {
- private static String user = ActiveMQConnection.DEFAULT_USER;
- private static String password =ActiveMQConnection.DEFAULT_PASSWORD;
- private static String url = "tcp://localhost:61616";
- public static void main(String[] args)throws Exception {
- // ConnectionFactory :連接工廠,JMS 用它創建連接
- ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
- // Connection :JMS 客戶端到JMS Provider 的連接
- Connection connection = connectionFactory.createConnection();
- // Connection 啓動
- connection.start();
- System.out.println("Connection is start...");
- // Session: 一個發送或接收消息的線程
- Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
- // Topicr :消息的目的地;消息發送給誰.
- Topic destination = session.createTopic("example.A");
- // MessageProducer:消息發送者
- MessageProducer producer = session.createProducer(destination);
- // 設置不持久化,此處學習,實際根據項目決定
- producer.setDeliveryMode(DeliveryMode.PERSISTENT);
- // 構造消息,此處寫死,項目就是參數,或者方法獲取
- sendMessage(session, producer);
- session.commit();
- connection.close();
- System.out.println("send text ok.");
- }
- public static void sendMessage(Session session, MessageProducer producer)
- throws Exception {
- for (int i = 1; i <= 100; i++) {//有限制,達到1000就不行
- TextMessage message = session.createTextMessage("ActiveMq 發送的消息" + i);
- // 發送消息到目的地方
- System.out.println("發送消息:" + "ActiveMq 發送的消息" + i);
- producer.send(message);
- }
- }
- }
5.Topic(發佈/訂閱)方式:訂閱者
- package jms;
- import javax.jms.Connection;
- import javax.jms.ConnectionFactory;
- import javax.jms.JMSException;
- import javax.jms.Message;
- import javax.jms.MessageConsumer;
- import javax.jms.MessageListener;
- import javax.jms.Session;
- import javax.jms.TextMessage;
- import javax.jms.Topic;
- import org.apache.activemq.ActiveMQConnection;
- import org.apache.activemq.ActiveMQConnectionFactory;
- //Topic(發佈/訂閱)方式 訂閱者TopicSubscriber
- public class TopicSubscriber {
- private static String user = ActiveMQConnection.DEFAULT_USER;
- private static String password =ActiveMQConnection.DEFAULT_PASSWORD;
- private static String url = "tcp://localhost:61616";
- public static void main(String[] args) throws Exception{
- // ConnectionFactory :連接工廠,JMS 用它創建連接
- ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
- // Connection :JMS 客戶端到JMS Provider 的連接
- Connection connection = connectionFactory.createConnection();
- connection.start();
- // Session: 一個發送或接收消息的線程
- final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
- // Destination :消息的目的地;消息發送給誰.
- Topic destination=session.createTopic("example.A");
- // 消費者,消息接收者
- MessageConsumer consumer = session.createConsumer(destination);
- consumer.setMessageListener(new MessageListener(){//有事務限制
- @Override
- public void onMessage(Message message) {
- try {
- TextMessage textMessage=(TextMessage)message;
- System.out.println(textMessage.getText());
- } catch (JMSException e1) {
- e1.printStackTrace();
- }
- try {
- session.commit();
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- });
- /* 另外一種接受方式
- * while (true) {
- //設置接收者接收消息的時間,爲了便於測試,這裏誰定爲100s
- TextMessage message = (TextMessage) consumer.receive(100000);
- if (null != message) {
- System.out.println("收到消息" + message.getText());
- } else {
- break;
- }
- }*/
- }
- }
Queue(點對點)方式和Topic(發佈/訂閱)方式 的運行結果最明顯的區別是:在Queue(點對點)方式中先運行生產者,再運行消費者,消費者還能接受到消息;
而Topic(發佈/訂閱)方式就不同了,先運行發佈者,再運行訂閱者,訂閱者收到的消息
可能沒有或者是不完全的。