Java中間件JMS之ActiveMQ入門

原文鏈接: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 

 

[java] view plaincopy
 
  1. if (message.getJMSReplyTo() != null) {    
  2.   replyProducer.send(message.getJMSReplyTo(),     
  3.  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(點對點)方式:生產者

[java] view plaincopy
 
  1. package jms;  
  2.   
  3. import javax.jms.Connection;  
  4. import javax.jms.ConnectionFactory;  
  5. import javax.jms.DeliveryMode;  
  6. import javax.jms.Destination;  
  7. import javax.jms.MessageProducer;  
  8. import javax.jms.Queue;  
  9. import javax.jms.Session;  
  10. import javax.jms.TextMessage;  
  11.   
  12. import org.apache.activemq.ActiveMQConnection;  
  13. import org.apache.activemq.ActiveMQConnectionFactory;  
  14.   
  15. //Queue(點對點)方式  生存者Producer  
  16. public class QueueProducer {  
  17.     private static String user = ActiveMQConnection.DEFAULT_USER;  
  18.     private static String password =ActiveMQConnection.DEFAULT_PASSWORD;  
  19.     private static String url =  "tcp://localhost:61616";  
  20.   
  21.     public static void main(String[] args)throws Exception {  
  22.          // ConnectionFactory :連接工廠,JMS 用它創建連接  
  23.         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);  
  24.         // Connection :JMS 客戶端到JMS Provider 的連接  
  25.         Connection connection = connectionFactory.createConnection();  
  26.         // Connection 啓動  
  27.         connection.start();  
  28.         System.out.println("Connection is start...");  
  29.         // Session: 一個發送或接收消息的線程  
  30.         Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);  
  31.         // Queue :消息的目的地;消息發送給誰.  
  32.         Queue  destination = session.createQueue("example.A");  
  33.         // MessageProducer:消息發送者  
  34.         MessageProducer producer = session.createProducer(destination);  
  35.         // 設置不持久化,此處學習,實際根據項目決定  
  36.         producer.setDeliveryMode(DeliveryMode.PERSISTENT);  
  37.          // 構造消息,此處寫死,項目就是參數,或者方法獲取  
  38.         sendMessage(session, producer);  
  39.         session.commit();  
  40.   
  41.         connection.close();  
  42.         System.out.println("send text ok.");  
  43.     }  
  44.       
  45.     public static void sendMessage(Session session, MessageProducer producer)  
  46.             throws Exception {  
  47.         for (int i = 1; i <= 100; i++) {//有限制,達到1000就不行  
  48.             TextMessage message = session.createTextMessage("ActiveMq 發送的消息" + i);  
  49.             // 發送消息到目的地方  
  50.             System.out.println("發送消息:" + "ActiveMq 發送的消息" + i);  
  51.             producer.send(message);  
  52.         }  
  53.     }  
  54. }  

  3.Queue(點對點)方式:消費者

 

[java] view plaincopy
 
  1. package jms;  
  2.   
  3. import javax.jms.Connection;  
  4. import javax.jms.ConnectionFactory;  
  5. import javax.jms.Destination;  
  6. import javax.jms.JMSException;  
  7. import javax.jms.Message;  
  8. import javax.jms.MessageConsumer;  
  9. import javax.jms.MessageListener;  
  10. import javax.jms.Queue;  
  11. import javax.jms.Session;  
  12. import javax.jms.TextMessage;  
  13.   
  14. import org.apache.activemq.ActiveMQConnection;  
  15. import org.apache.activemq.ActiveMQConnectionFactory;  
  16.   
  17. //Queue(點對點)方式  消費這Consumer  
  18. public class QueueConsumer {  
  19.     private static String user = ActiveMQConnection.DEFAULT_USER;  
  20.     private static String password =ActiveMQConnection.DEFAULT_PASSWORD;  
  21.     private static String url = "tcp://localhost:61616";  
  22.     public static void main(String[] args) throws Exception{  
  23.         // ConnectionFactory :連接工廠,JMS 用它創建連接  
  24.         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);  
  25.         // Connection :JMS 客戶端到JMS Provider 的連接  
  26.         Connection connection = connectionFactory.createConnection();  
  27.         connection.start();  
  28.         // Session: 一個發送或接收消息的線程  
  29.         final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);  
  30.         // Destination :消息的目的地;消息發送給誰.  
  31.         Queue destination=session.createQueue("example.A");  
  32.         // 消費者,消息接收者  
  33.         MessageConsumer consumer = session.createConsumer(destination);  
  34.         consumer.setMessageListener(new MessageListener(){//有事務限制  
  35.             @Override  
  36.             public void onMessage(Message message) {  
  37.                 try {  
  38.                     TextMessage textMessage=(TextMessage)message;  
  39.                     System.out.println(textMessage.getText());  
  40.                 } catch (JMSException e1) {  
  41.                     e1.printStackTrace();  
  42.                 }  
  43.                 try {  
  44.                     session.commit();  
  45.                 } catch (JMSException e) {  
  46.                     e.printStackTrace();  
  47.                 }  
  48.             }  
  49.         });  
  50.           
  51. /*  另外一種接受方式 
  52.  *    while (true) { 
  53.               //設置接收者接收消息的時間,爲了便於測試,這裏誰定爲100s 
  54.               TextMessage message = (TextMessage) consumer.receive(100000); 
  55.               if (null != message) { 
  56.                   System.out.println("收到消息" + message.getText()); 
  57.               } else { 
  58.                   break; 
  59.               } 
  60.           }*/  
  61.     }  
  62. }  

 

 

 

 4.Topic(發佈/訂閱)方式:發佈者

 

[java] view plaincopy
 
  1. package jms;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import javax.jms.Connection;  
  6. import javax.jms.ConnectionFactory;  
  7. import javax.jms.DeliveryMode;  
  8. import javax.jms.JMSException;  
  9. import javax.jms.MapMessage;  
  10. import javax.jms.MessageProducer;  
  11. import javax.jms.Queue;  
  12. import javax.jms.Session;  
  13. import javax.jms.TextMessage;  
  14. import javax.jms.Topic;  
  15.   
  16. import org.apache.activemq.ActiveMQConnection;  
  17. import org.apache.activemq.ActiveMQConnectionFactory;  
  18.   
  19. //Topic(發佈/訂閱)方式  發佈者Publisher  
  20. public class TopicPublisher {  
  21.     private static String user = ActiveMQConnection.DEFAULT_USER;  
  22.     private static String password =ActiveMQConnection.DEFAULT_PASSWORD;  
  23.     private static String url =  "tcp://localhost:61616";  
  24.   
  25.     public static void main(String[] args)throws Exception {  
  26.          // ConnectionFactory :連接工廠,JMS 用它創建連接  
  27.         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);  
  28.         // Connection :JMS 客戶端到JMS Provider 的連接  
  29.         Connection connection = connectionFactory.createConnection();  
  30.         // Connection 啓動  
  31.         connection.start();  
  32.         System.out.println("Connection is start...");  
  33.         // Session: 一個發送或接收消息的線程  
  34.         Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);  
  35.         // Topicr :消息的目的地;消息發送給誰.  
  36.         Topic  destination = session.createTopic("example.A");  
  37.         // MessageProducer:消息發送者  
  38.         MessageProducer producer = session.createProducer(destination);  
  39.         // 設置不持久化,此處學習,實際根據項目決定  
  40.         producer.setDeliveryMode(DeliveryMode.PERSISTENT);  
  41.          // 構造消息,此處寫死,項目就是參數,或者方法獲取  
  42.         sendMessage(session, producer);  
  43.         session.commit();  
  44.   
  45.         connection.close();  
  46.         System.out.println("send text ok.");  
  47.     }  
  48.       
  49.     public static void sendMessage(Session session, MessageProducer producer)  
  50.             throws Exception {  
  51.         for (int i = 1; i <= 100; i++) {//有限制,達到1000就不行  
  52.             TextMessage message = session.createTextMessage("ActiveMq 發送的消息" + i);  
  53.             // 發送消息到目的地方  
  54.             System.out.println("發送消息:" + "ActiveMq 發送的消息" + i);  
  55.             producer.send(message);  
  56.         }  
  57.     }  
  58.   
  59. }  



 

 

 

 5.Topic(發佈/訂閱)方式:訂閱者

 

 

[java] view plaincopy
 
  1. package jms;  
  2.   
  3. import javax.jms.Connection;  
  4. import javax.jms.ConnectionFactory;  
  5. import javax.jms.JMSException;  
  6. import javax.jms.Message;  
  7. import javax.jms.MessageConsumer;  
  8. import javax.jms.MessageListener;  
  9. import javax.jms.Session;  
  10. import javax.jms.TextMessage;  
  11. import javax.jms.Topic;  
  12.   
  13. import org.apache.activemq.ActiveMQConnection;  
  14. import org.apache.activemq.ActiveMQConnectionFactory;  
  15.   
  16. //Topic(發佈/訂閱)方式  訂閱者TopicSubscriber  
  17. public class TopicSubscriber {  
  18.     private static String user = ActiveMQConnection.DEFAULT_USER;  
  19.     private static String password =ActiveMQConnection.DEFAULT_PASSWORD;  
  20.     private static String url = "tcp://localhost:61616";  
  21.     public static void main(String[] args) throws Exception{  
  22.         // ConnectionFactory :連接工廠,JMS 用它創建連接  
  23.         ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);  
  24.         // Connection :JMS 客戶端到JMS Provider 的連接  
  25.         Connection connection = connectionFactory.createConnection();  
  26.         connection.start();  
  27.         // Session: 一個發送或接收消息的線程  
  28.         final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);  
  29.         // Destination :消息的目的地;消息發送給誰.  
  30.         Topic destination=session.createTopic("example.A");  
  31.         // 消費者,消息接收者  
  32.         MessageConsumer consumer = session.createConsumer(destination);  
  33.         consumer.setMessageListener(new MessageListener(){//有事務限制  
  34.             @Override  
  35.             public void onMessage(Message message) {  
  36.                 try {  
  37.                     TextMessage textMessage=(TextMessage)message;  
  38.                     System.out.println(textMessage.getText());  
  39.                 } catch (JMSException e1) {  
  40.                     e1.printStackTrace();  
  41.                 }  
  42.                 try {  
  43.                     session.commit();  
  44.                 } catch (JMSException e) {  
  45.                     e.printStackTrace();  
  46.                 }  
  47.             }  
  48.         });  
  49.           
  50. /*  另外一種接受方式 
  51.  *    while (true) { 
  52.               //設置接收者接收消息的時間,爲了便於測試,這裏誰定爲100s 
  53.               TextMessage message = (TextMessage) consumer.receive(100000); 
  54.               if (null != message) { 
  55.                   System.out.println("收到消息" + message.getText()); 
  56.               } else { 
  57.                   break; 
  58.               } 
  59.           }*/  
  60.     }  
  61. }  

 

 

 

Queue(點對點)方式和Topic(發佈/訂閱)方式 的運行結果最明顯的區別是:Queue(點對點)方式中先運行生產者,再運行消費者,消費者還能接受到消息;

Topic(發佈/訂閱)方式就不同了,先運行發佈者,再運行訂閱者,訂閱者收到的消息

可能沒有或者是不完全的。

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