JMS入門


1 基本信息

摘要:本篇爲JMS的學習筆記, 教你一步一步使用JMS,並提供一個能運行的完整的案例,可以使人達到快速入門的目的。

2 正文

  JMS(Java Message Service),是Java消息服務,通過JMS,可以在Java對象之間發送消息。JMS消息支持點對點之間的消息發送,也支持主題/訂閱方式的消息發送。

  /** 注: 本筆記中的代碼針在jboss4.0.5下運行通過 */

  消息服務由客戶和消息代理組成。每位客戶都連接到消息服務,客戶可以創建消息、發送消息、接收消息、閱讀消息。消息服務可以將接收到的消息轉發給其他的客戶。

  消息服務的關鍵特點:客戶只需要最少的信息就可以其他客戶通信(需知道其他客戶的提供的服務、服務所需信息和客戶地址)。

  消息服務使用轉發-存儲結構以提交異步信息。

  JMS包含5個元素:

•  提供者: 負責管理消息服務的消息代理
•  客戶:   java編寫的,利用提供者進行通信的應用程序和組件
•  消息:   在客戶之間傳輸的對象
•  管理的對象: 傳輸中使用的jms對象,分兩種,目標工廠(Destination Factory)對象和連接對象,用於連接消息服務,處理髮送者和接收者之間的傳輸。
•  本機客戶: 是在引入jms之前構建的應用程序,它們是採用另外一種消息系統的本機客戶API

  在引入jms之前,客戶是用 點對點 和 訂閱/發佈結構

  jms的5個元素:

•  管理對象: 連接工廠(Connection Factory)對象和會話對象;連接工廠對象用於創建會話對象;會話對象用於創建發送者和接收者
    ConnectionFactory(QueueConnectionFactory,TopicConnectionFactoy,XAQueueConnectionFactory,XATopicConnectionFactoy)
    Connection(QueueConnection,TopicConnection,XAQueueConnection,XATopicConnection)
•  會話:   Session
•  消息生成者: MessageProducer(QueueSender, TopicPublisher)
•  消息使用者: MessageConsumer(QueueReciever,TopicSubscriber)
•  消息:   Message

  jms使用步驟:

1 訪問連接工廠:

  1. InitialContext ctx=new InitialContext();
  2. TopicConnectionFactory tcf=(TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");
  3. QueueConnectionFactory qcf=(QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");

2 訪問目標工廠:創建Queue對象/Topic對象

  1. Topic mt=(Topic) ctx.lookup("topic/testTopic");
  2. Queue mq=(Queue) ctx.lookup("queue/A");

3 創建連接,分兩種:隊列連接和主題連接

  1. TopicConnection tc=tcf.createTopicConnection();
  2. QueueConnection qc=qcf.createQueueConnection();

4. 開始接收:也可以放在後面進行

  1. tc.start(); //以後需要調用 tc.close(); 關閉連接
  2. qc.start(); //以後需要調用 qc.close(); 關閉連接

5. 創建會話:會話用於創建消息生產者、消息消費者、消息。

  1. QueueSession qSession=qc.createQueueSession(true,0);
  2. TopicSession tSession=tc.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);

參數1:是否使用事務
參數2:消息確認模式

  當消息發送者向消息提供者(即消息代理)發送消息時,消息發送者等待消息代理的確認,沒有迴應則拋出異常,消息發送程序負責處理這個錯誤。

  注:消息代理確認只是確認收到了消息,而不是確認消息提交給了消息接收者。

  消息確認模式:JMS使用確認協議以保證消息的發送,使用了3種確認模式

AUTO_ACKNOWLEDGE : 指定消息提供者在每次收到消息時自動發送確認。消息只向目標發送一次,但傳輸過程中可能因爲錯誤而丟失消息。
CLIENT_ACKNOWLEDGE : 由消息接收者確認收到消息,通過調用消息的acknowledge()方法(會通知消息提供者收到了消息)
DUPS_OK_ACKNOWLEDGE : 指定消息提供者在消息接收者沒有確認發送時重新發送消息(這種確認模式不在乎接收者收到重複的消息)。如

   消息提供者在試圖向非持久化的消息接收者發送消息失敗時,消息會丟失。在向持久化消息接收者發送消息時,會等待消息接收者確認,未收到確認,則重新發送 消息(消息提供者需要設置JMSRedilivered=true,消息接收者需要調用Message對象的getJMSRedelivered()方法 確認JMSRedilivered標記是否爲true)

CLIENT_ACKNOWLEDGE 確認收到消息代碼:

  1. public void onMessage(Message msg){
  2. try{
  3. //Process incoming messages
  4. msg.acknowledge();
  5. }catch(Exception e){
  6. //handle error
  7. }
  8. }

  消息事務: 包含一組消息,要麼全部發送,要不全部都不發送給消息提供者。

  消息提供者緩存消息,如果消息發送者有一個消息發送失敗,則調用session.rollback()方法,則消息提供者會放棄前面發送成功的消息;如果全部發送成功,調用session.commit()方法,將消息全部發送給消息接收者。

6 創建消息生產者:

  1. QueueSender qSender=qSession.createSender(mq);
  2. TopicPublisher tPublisher=tSession.createPublisher(mt);
  3. qSender.send(msg);
  4. tPublisher.publish(msg);

7 創建消息使用者:在接收任何消息之前,客戶必須註冊到JMS提供者表明希望接收消息。註冊後,JMS提供者就負責向客戶發送消息。

  1. QueueReceiver qr=qSession.createReceiver(mq);
  2. qc.start();
  3. Message msg1=qr.receive();
  4. TopicSubscriber tSubscriber=tSession.createSubscriber(mt);
  5. tc.start();
  6. Message msg2=tSubscriber.receive(1500); //每隔1500毫秒從主題接收一次

8 創建消息監聽器(實現MessageListener接口onMessage()方法):消息使用者通過消息監聽器異步接收消息。

  1. QueueListener qListener=new QueueListener(); //QueueListener爲自定義類,實現MessageListener接口
  2. qr.setMessageListener(qListener);
  3. TopicListener tListener=new TopicListener(); //TopicListener爲自定義類,實現MessageListener接口
  4. tSubscriber.setMessageListener(tListener);

9 消息(Message):三部分,頭(必須的),屬性和正文 (二者爲可選)。

  消息頭讀寫方法: getXXX(),setXXX()

  XXX是字段的名字,許多消息字段是由send()和publish()方法自動設置的,其他自動則由客戶或者JMS程序設置。

1) 由send() or publish()設置的:

  1. JMSDestination
  2. JMSDeliveryMode
  3. JMSExpiration
  4. JMSPriority
  5. JMSMessageID
  6. JMSTimestamp
  7. JMSCorrelationID: 關聯消息ID
  8. JMSReplyTo
  9. JMSType
  10. JMSRedelivered

2)由客戶設置的:

  1. JMSCorrelationID: 關聯消息ID
  2. JMSReplyTo
  3. JMSType

3) 由jms提供者設置的:

  1. JMSRedelivered

## 屬性讀寫方法:   getXXX(name), setXXX(name,value)

  消息正文:包含消息,JMS支持6種消息格式,稱爲消息類型

TextMessage:   有文本組成的String對象
MapMessage:   可以是按順序或隨機訪問的 key-value對,key爲String, value爲primitive
BytesMessage: 字節信息(如存放圖像)
StreamMessage: 包含順序讀取值的流
ObjectMessage: 可以序列化的java對象
Message:   無消息正文時可以使用

創建TextMessage消息:

  1. TextMessage msg=qSession.createTextMessage();
  2. msg.setText("myMessage");
  3. qSender.send(msg);

讀取TextMessage消息:

  1. Message msg=qr.receive();
  2. if(msg instanceof TextMessage){
  3. TextMessage txtMsg=(TextMessage) msg;
  4. System.out.println("Imcoming message: "+txtMsg.getText());
  5. }else{
  6. //handle error
  7. }

10. 消息選擇器:消息使用者使用消息選擇器(message selector)選擇收到的消息。消息選擇器使用條件表達式(符合WHERE子句的SQL-92標準)作爲選擇條件。
創建並使用消息選擇器:

  1. String criteria="Customer='1234'";
  2. TopicSubscriber tSubscriber=ts.createSubscriber(myTopic,criteria,false); //只從主題中接收Customer='1234'的消息

### 向隊列發送消息

  1. SendToQueue.java:
  2. package test.jms;
  3. import java.util.Properties;
  4. import javax.jms.*;
  5. import javax.naming.*;
  6. public class SendToQueue {
  7. public static void main(String[] args) {
  8. final int msgCount;
  9. if( (args.length<1) || ( args.length>2)) {
  10. System.out.println("Usage: java test.jms.SendToQueue queueName [sendCount]");
  11. System.exit(1);
  12. }
  13. String qName=new String(args[0]);
  14. if(args.length==2) {
  15. msgCount=(new Integer(args[1]).intValue());
  16. }else {
  17. msgCount=1;
  18. }
  19. QueueConnection qc=null;
  20. try {
  21. Properties p = new Properties();
  22. p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
  23. "org.jnp.interfaces.NamingContextFactory");
  24. p.setProperty(Context.PROVIDER_URL, "localhost:1099");
  25. InitialContext jc=new InitialContext(p);
  26. QueueConnectionFactory qcf=(QueueConnectionFactory)jc.lookup("QueueConnectionFactory");
  27. Queue q=(Queue)jc.lookup(qName);
  28. qc=qcf.createQueueConnection();
  29. QueueSession qs=qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
  30. QueueSender qSender=qs.createSender(q);
  31. TextMessage msg=qs.createTextMessage();
  32. for(int i=0;i<msgCount;i++) {
  33. msg.setText("Welcome number "+(i+1));
  34. qSender.send(msg);
  35. System.out.println("Send Message To "+qName+" : "+msg.getText()+"\n");
  36. }
  37. qSender.close();
  38. qs.close();
  39. }catch(Exception e) {
  40. e.printStackTrace();
  41. }finally {
  42. if(qc!=null) {
  43. try {
  44. qc.close();
  45. }catch(JMSException e) {}
  46. }
  47. }
  48. }
  49. }

運行: java test.jms.SendToQueue queue/A 10

### 從隊列接收消息

  1. ReceiveFromQueue.java:
  2. package test.jms;
  3. import java.io.*;
  4. import java.util.Properties;
  5. import javax.jms.*;
  6. import javax.naming.*;
  7. public class ReceiveFromQueue {
  8. public static void doReceive(String qName) {
  9. Message msg;
  10. TextMessage txtMsg;
  11. QueueConnection qc = null;
  12. try {
  13. Properties p = new Properties();
  14. p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
  15. "org.jnp.interfaces.NamingContextFactory");
  16. p.setProperty(Context.PROVIDER_URL, "localhost:1099");
  17. InitialContext jc = new InitialContext(p);
  18. QueueConnectionFactory qcf = (QueueConnectionFactory) jc
  19. .lookup("QueueConnectionFactory");
  20. Queue q = (Queue) jc.lookup(qName);
  21. qc = qcf.createQueueConnection();
  22. QueueSession qs = qc.createQueueSession(false,
  23. Session.AUTO_ACKNOWLEDGE);
  24. QueueReceiver qr = qs.createReceiver(q);
  25. qc.start();
  26. System.out.println("begin receive messge from " + qName + "...");
  27. msg = qr.receive(1000); // 如果不加間隔參數,會一直等着,知道消息到來。
  28. while (msg != null) {
  29. if (msg instanceof TextMessage) {
  30. txtMsg = (TextMessage) msg;
  31. System.out.println("Receive Msg from " + qName + " : "
  32. + txtMsg.getText());
  33. }
  34. msg = qr.receive(1000);
  35. }
  36. System.out.println("no message available!");
  37. qr.close();
  38. qs.close();
  39. } catch (Exception e) {
  40. e.printStackTrace();
  41. } finally {
  42. if (qc != null) {
  43. try {
  44. qc.close();
  45. } catch (JMSException e) {
  46. }
  47. }
  48. }
  49. }
  50. public static void doListen(String qName) {
  51. Message msg;
  52. TextMessage txtMsg;
  53. QueueConnection qc = null;
  54. try {
  55. Properties p = new Properties();
  56. p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
  57. "org.jnp.interfaces.NamingContextFactory");
  58. p.setProperty(Context.PROVIDER_URL, "localhost:1099");
  59. InitialContext jc = new InitialContext(p);
  60. QueueConnectionFactory qcf = (QueueConnectionFactory) jc
  61. .lookup("QueueConnectionFactory");
  62. Queue q = (Queue) jc.lookup(qName);
  63. qc = qcf.createQueueConnection();
  64. QueueSession qs = qc.createQueueSession(false,
  65. Session.AUTO_ACKNOWLEDGE);
  66. QueueReceiver qr = qs.createReceiver(q);
  67. qc.start();
  68. System.out.println("begin listen to messge from " + qName + "...");
  69. TextListener tListener = new TextListener();
  70. qr.setMessageListener(tListener);
  71. qc.start();
  72. System.out.println("Enter 'q' and press <return> to exit ");
  73. InputStreamReader isr = new InputStreamReader(System.in);
  74. char response = '\0';
  75. while (!((response == 'q') || (response == 'Q'))) {
  76. try {
  77. response = (char) isr.read();
  78. } catch (IOException e) {
  79. e.printStackTrace();
  80. }
  81. }
  82. System.out.println("End listening!");
  83. qr.close();
  84. qs.close();
  85. } catch (Exception e) {
  86. e.printStackTrace();
  87. } finally {
  88. if (qc != null) {
  89. try {
  90. qc.close();
  91. } catch (JMSException e) {
  92. }
  93. }
  94. }
  95. }
  96. public static void main(String[] args) {
  97. if ((args.length != 1)) {
  98. System.out
  99. .println("Usage: java test.jms.ReceiveFromQueue queueName");
  100. System.exit(1);
  101. }
  102. String qName = new String(args[0]);
  103. doReceive(qName); //通過QueueReceiver.receive()讀消息
  104. doListen(qName); // 通過消息監聽器讀消息
  105. }
  106. }

原文地址:http://wenku.baidu.com/view/2eccd9a10029bd64783e2c24.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章