JMS簡明學習教程

基礎篇

JMS是應用系統或組件之間相互通信的應用程序接口,利用它,我們可以輕易實現在不同JVM之間相互的遠程通信。要實現遠程通信,RPC同樣也能做到,但RPC卻不可避免地增加了不同系統之間的耦合度,JMS能極大地降低不同的應用系統之間的耦合。

 

要學習JMS,有幾個概念必須要搞清楚:

l      Messaging (消息通知、消息通信)

一種應用系統或組件之間相互通信的方式。

 

l      Message (消息)

消息即爲消息通信的載體,消息包括Message Headers, Message properties, Message bodies

 

l      JMS有兩種方式進行消息通信:Point-to-Point (P2P)  Publish/Subscriber (PUB/SUB)

 

P2P方式是一對一的,一條消息只有一個接收者,默認情況下是P2P消息是持久的,也就是說發送者(sender)產生的一條消息(message)發送到消息隊列(queue)之上後,只有等到消息接收者(receiver)接收到它,纔會從消息隊列中刪除,沒有被接收的消息會一直存在JMS容器裏。這種方式有點像郵政通信,信件只有一個接收者,信件在接收之前,會一直存放在信箱裏。

 

PUB/SUB方式的工作流程,首先subscriber(訂閱者)向JMS容器訂閱(Listen to)自己感興趣的topic(主題),多個訂閱者可以同時對一個主題進行訂閱,消息發佈者發佈一條消息,所有訂閱了該主題的訂閱者都能收到這個消息。默認情況下,pub/sub方式下的消息不是持久的,這意味着,消息一經發出,不管有沒有人接收,都不會保存下來,而且訂閱者只能接收到自已訂閱之後發佈者發出的消息。這種方式有點像訂閱報刊雜誌,一種報刊可以有多人同時訂閱,但訂閱者只能收到開始訂閱之後的報社發行的期刊。

 

l      JMSJava Messaging Service

Java EE中的一種技術,它定義一套完整的接口,來實現不同系統或應用之間的消息通信。這意味着:我們針對JMS接口編寫的應用程序(客戶程序),在任何一個實現了標準JMS接口的容器下都能運行起來,我們的應用程序與容器實現了真正的解藕,這也就是面向接口編程的好處之一吧。這點類似JDBC編程。

 

l      JMS提供者(JMS Provider

JMS提供者,也叫JMS服務器或JMS容器,也就是JMS服務的提供者,主流的J2EE容器一般都提供JMS服務(比如JBossBEA WebLogicIBM WebSphereOracle Application Server等都支持)

 

l      連接工廠(Connection Factories

連接工廠是用來創建客戶端到JMS容器之間JMS連接的工廠,連接工廠有兩種:(QueueConnectionFactoryTopicConnectionFactory),分別用來創建QueueConnection  TopicConnection的。

 

Context ctx = new InitialContext();
QueueConnectionFactory queueConnectionFactory = 
                    (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
TopicConnectionFactory topicConnectionFactory = 
                    (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");  

l      目的地(Destinations

目的地是消息生產者(producer)消息發住的目的地,也是消費者(consumer)接收消息的來源地,它有點像信箱,郵遞員把信件投往信箱,收件人從信箱取信件。對P2P方式來說,目的地就是Queue,對pub/sub方式來說,目的地就是Topic。我們要得到這個目的地的引用,只能通過JNDI查找(lookup)的方式得到,因爲目的地是註冊在JMS服務器的(後面的章節會講到如何註冊一個目的地)

 

Topic myTopic = (Topic) ctx.lookup("MyTopic");
Queue myQueue = (Queue) ctx.lookup("MyQueue");

 

l      連接(Connection

這裏說的連接是指客戶端與JMS提供者(容器)之間的連接。連接也分兩種:QueueConnectionTopicConnection,分別對應於P2P連接和Pub/Sub連接。

 

QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();

 

連接用完之後必須記得關閉,否則連接資源不會被釋放掉。關閉連接的同時會自動把會話、產生者、消費者都關閉掉。

 

l      會話(Session

會話是用來創建消息產生者和消息消費者的單線程環境,你可以它來創建消息生產者、消費者、消息,用它來維持消息監聽。

 

TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSession queueSession = queueConnection.createQueueSession(true, 0);

l      消息生產者(Message Producers

消息生產者也就是消息的產生者或發送者,在P2P方式下它是QueueSender,在Pub/Sub方式下它是TopicPublisher它是一個由session創建的,用來把把消息發送到目的地的對象。

QueueSender queueSender = queueSession.createSender(myQueue);
TopicPublisher topicPublisher = topicSession.createPublisher(myTopic);

 

一旦你創建好生產者,你就可以用它來發送消息

queueSender.send(message);
topicPublisher.publish(message);

 

 

l      消息消費者(Message Consumer

消息消費者也就是消息的接收者或使用者,在P2P方式下這是QueueReceiver,在Pub/Sub方式下它是TopicSubscriber。這是一個由session來創建的,用來接收來自目的地消息的對象。JMS容器來負責把消息從目的地投遞到註冊了該目的地的消息消費者。

 

QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);
TopicSubscriber topicSubscriber = topicSession.createSubscriber(myTopic);

 

一旦創建好消息消費者,它就是活動的,你可以用它來接收消息,你也可以用close()方法來使它失效(Inactive)。當你調用Connectionstart()方法之前,消費者是不會接收到任何消息的。兩種接收者都有一個receive方法,這是一個同步的方法,也就是說程序執行到這個方法會被阻塞,直到收到消息爲止。

queueConnection.start();
Message m = queueReceiver.receive(); 
topicConnection.start();
Message m = topicSubscriber.receive(1000); // time out after a second

 

如果我們不想它被阻塞,就需要異步的接收消息,這時我們得用消息臨聽器(Message Listener)了。

 

 

l      消息監聽器(Message Listener

消息監聽器是一個充當消息的異步事件處理器的對象,它實現了MessageListener接口,這個接口只有一個方法onMessage,在這個方法裏,你可以定義當接收到消息之後的要做的操作。你可以用setMessageListener方法爲消息消費者註冊一個監聽器。

 

MessageListener listener = new MessageListener( {
      public void onMessage(Message msg) {
          //
      }
});
topicSubscriber.setMessageListener(listener); //註冊監聽
topicConnection.start();

有一點要注意,如果你先調用Connectionstart,然後再調用setMessageListener,消息很可能接收不到,正確的做法是先註冊監聽,再啓動Connection

 

註冊監聽之後,一旦JMS容器有消費投遞過來,消息消費(接收)者就會自動調用監聽器的onMessage方法。這個方法的帶有一個參數Message,這就接收到的消息。

 

 

l      消息選擇器(Message Selectors

假如你只需要一個對濾器來過濾收到的消息,那麼你可以使用消息選擇器,它允許消費者指定只對特定的消息感興趣。消息選擇器只能是工作在JMS容器的,而不是我們的應用程序上。消息選擇器是一個包含一個表達式的字符串,這個表達式的語法類似SQL的條件表達式,在createReceiver, createSubscriber這些方法裏有一個參數讓你指定一個消息選擇器,由這些方法創建的消費者就只能收到與消息選擇器匹配的消息了。

 

 

l      消息(Messages

JMS消息包括三個部分:消息頭(Header),屬性(Properties),消息體(Body

其中消息頭是必須的,後兩個是可選的。

1)消息頭裏你可以指定JMSMessageID, JMSCorrelationID, JMSReplyTo, JMSType等信息。

2)屬性指定一些消息頭沒有包括的附加信息,比如可以在屬性裏指定消息選擇器。

3)消息體是消息的內容,有5種消息類型:TextMessageMapMessageBytesMessageStreamMessageObjectMessage=-

 

TextMessage message = queueSession.createTextMessage();
message.setText(msg_text);     // msg_text is a String
queueSender.send(message); 

在消費者端,接收到的總是一個通用的Message對象,你需要把它轉型成特定的類型才能提取出裏面的內容。

Message m = queueReceiver.receive();
if (m instanceof TextMessage) {
    TextMessage message = (TextMessage) m;
    System.out.println("Reading message: " + message.getText());
} else {
    // Handle error}

 

 

 

 

 

 實戰篇

前面對JMS概念的作了一個基本介紹,下面我們看一個具體的例子程序

 

Pub/sub方式的消息傳遞的例子:

l         HelloPublisher.java

 

package com.jms.test;

 

import java.util.Hashtable;

 

import javax.jms.JMSException;

import javax.jms.Session;

import javax.jms.TextMessage;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicPublisher;

import javax.jms.TopicSession;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

/**

 * pub/sub方式的消息發送程序

 */

public class HelloPublisher {

   

    TopicConnection topicConnection;// JMS連接,屬於Pub/Sub方式的連接

    TopicSession topicSession//JMS會話,屬於Pub/Sub方式的會話

    TopicPublisher topicPublisher//消息發佈者

    Topic topic//主題

   

    public HelloPublisher(String factoryJNDI, String topicJNDI)

           throws JMSException, NamingException {

       Hashtable<String, String> env = new Hashtable<String, String>();

       //設置好連接JMS容器的屬性,不同的容器需要的屬性可能不同,需要查閱相關文檔

       env.put(Context.INITIAL_CONTEXT_FACTORY,

              "org.jnp.interfaces.NamingContextFactory");

       env.put(Context.PROVIDER_URL"localhost:1099");

       env.put("java.naming.rmi.security.manager""yes");

       env.put(Context.URL_PKG_PREFIXES"org.jboss.naming");

 

       //創建連接JMS容器的上下文(context)

       Context context = new InitialContext(env);

 

       //通過連接工廠的JNDI名查找ConnectionFactory

       TopicConnectionFactory topicFactory =

           (TopicConnectionFactory) context.lookup(factoryJNDI);

 

       //用連接工廠創建一個JMS連接

       topicConnection = topicFactory.createTopicConnection();

 

       //通過JMS連接創建一個Session

       topicSession = topicConnection.createTopicSession(false,

              Session.AUTO_ACKNOWLEDGE);

 

       //通過上下文查找到一個主題(topic)

       topic = (Topic) context.lookup(topicJNDI);

 

       //session來創建一個特定主題的消息發送者

       topicPublisher = topicSession.createPublisher(topic);

    }

   

 

    /**

     * 發佈一條文本消息

     * @param msg 待發布的消息

     * @throws JMSException

     */

    public void publish(String msg) throws JMSException {

       //session來創建一個文本類型的消息

       TextMessage message = topicSession.createTextMessage();

       message.setText(msg);//設置消息內容

       topicPublisher.publish(topic, message);//消息發送,發送到特定主題

    }

 

    public void close() throws JMSException {

       topicSession.close();//關閉session

       topicConnection.close();//關閉連接

    }

 

    public static void main(String[] args)

       throws JMSException, NamingException {

       HelloPublisher publisher =

           new HelloPublisher("ConnectionFactory""topic/testTopic");

       try {

           for (int i = 1; i < 11; i++) {

              String msg = "Hello World no. " + i;

              System.out.println("Publishing message: " + msg);

              publisher.publish(msg);

           }

           publisher.close();//sessionconnection用完之後一定記得關閉

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

}

程序在控制檯輸出:

Publishing message: Hello World no. 1

Publishing message: Hello World no. 2

Publishing message: Hello World no. 3

Publishing message: Hello World no. 4

Publishing message: Hello World no. 5

Publishing message: Hello World no. 6

Publishing message: Hello World no. 7

Publishing message: Hello World no. 8

Publishing message: Hello World no. 9

Publishing message: Hello World no. 10

 

 

l        HelloSubscriber.java

 

package com.jms.test;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Session;

import javax.jms.TextMessage;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicSession;

import javax.jms.TopicSubscriber;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

/**

 * pub/sub方式下的消息接收器。注意,這個消息接收器可以與上面的消息發送器可以工作

在不同的JVM中,只要保證它們各自能夠連通JMS容器(JMS Provider)

 *

 */

public class HelloSubscriber implements MessageListener {

    TopicConnection topicConnection;

    TopicSession topicSession;

    TopicSubscriber topicSubscriber;

    Topic topic;

 

    public HelloSubscriber(String factoryJNDI, String topicJNDI)

           throws JMSException, NamingException {

Hashtable<String, String> env = new Hashtable<String, String>();

       //設置好連接JMS容器的屬性,不同的容器需要的屬性可能不同,需要查閱相關文檔

       env.put(Context.INITIAL_CONTEXT_FACTORY,

              "org.jnp.interfaces.NamingContextFactory");

       env.put(Context.PROVIDER_URL"localhost:1099");

       env.put("java.naming.rmi.security.manager""yes");

       env.put(Context.URL_PKG_PREFIXES"org.jboss.naming");

       Context context = new InitialContext();

 

       TopicConnectionFactory topicFactory =

           (TopicConnectionFactory) context.lookup(factoryJNDI);

       //創建連接

       topicConnection = topicFactory.createTopicConnection();

       topicSession = topicConnection.createTopicSession(false,

              Session.AUTO_ACKNOWLEDGE);//創建session

       topic = (Topic) context.lookup(topicJNDI);//查找到主題

       //session創建一個特定queue的消息接收者

       topicSubscriber = topicSession.createSubscriber(topic);

       //註冊監聽,這裏設置的監聽是自己,因爲本類已經實現了MessageListener接口,

       //一旦queueReceiver接收到了消息,就會調用本類的onMessage方法

       topicSubscriber.setMessageListener(this);

       System.out.println("HelloSubscriber subscribed to topic: "

              + topicJNDI);

       topicConnection.start();//啓動連接,這時監聽器才真正生效

    }

 

    public void onMessage(Message msg) {

       try {

           if (msg instanceof TextMessage) {

              //Message 轉型成 TextMessage 並提取消息內容

              String msgTxt = ((TextMessage) msg).getText();

              System.out.println("HelloSubscriber got message: " +

                  msgTxt);

           }

       } catch (JMSException ex) {

           System.err.println("Could not get text message: " + ex);

           ex.printStackTrace();

       }

    }

 

    public void close() throws JMSException {

       topicSession.close();

       topicConnection.close();

    }

 

    public static void main(String[] args) {

       try {

           new HelloSubscriber("TopicConnectionFactory",

              "topic/testTopic");

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

}

程序在控制檯輸出:

HelloSubscriber subscribed to topic: topic/testTopic

HelloSubscriber got message: Hello World no. 1

HelloSubscriber got message: Hello World no. 2

HelloSubscriber got message: Hello World no. 3

HelloSubscriber got message: Hello World no. 4

HelloSubscriber got message: Hello World no. 5

HelloSubscriber got message: Hello World no. 6

HelloSubscriber got message: Hello World no. 7

HelloSubscriber got message: Hello World no. 8

HelloSubscriber got message: Hello World no. 9

HelloSubscriber got message: Hello World no. 10

 

 

 

P2P方式下的消息傳遞

l         HelloQueue.java

 

package com.jms.test;

 

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueConnection;

import javax.jms.QueueSession;

import javax.jms.QueueSender;

import javax.jms.Queue;

import javax.jms.TextMessage;

import javax.jms.Session;

import javax.jms.JMSException;

 

import java.util.Hashtable;

 

public class HelloQueue {

    QueueConnection queueConnection//queue方式的JMS連接

    QueueSession queueSession//queue會話

    QueueSender queueSender//queue消息發送者

    Queue queue//消息隊列

 

    public HelloQueue(String factoryJNDI, String topicJNDI)

            throws JMSException, NamingException {

        //連接JMS Provider的環境參數

        Hashtable<String, String> props = new Hashtable<String, String>();

        props.put(Context.INITIAL_CONTEXT_FACTORY,

                "org.jnp.interfaces.NamingContextFactory");

        //JMS provider的主機和端口

        props.put(Context.PROVIDER_URL"localhost:1099");

        props.put("java.naming.rmi.security.manager""yes");

        props.put(Context.URL_PKG_PREFIXES"org.jboss.naming");

        Context context = new InitialContext(props);

       

        //lookup到連接工廠

        QueueConnectionFactory queueFactory =

            (QueueConnectionFactory) context.lookup(factoryJNDI);

        queueConnection = queueFactory.createQueueConnection();//創建連接

        queueSession = queueConnection.createQueueSession(false,

                Session.AUTO_ACKNOWLEDGE);//創建會話

 

        queue = (Queue) context.lookup(topicJNDI);//lookup到特定的消息隊列

 

        queueSender = queueSession.createSender(queue);//創建隊列消息的發送者

 

    }

 

    public void send(String msg) throws JMSException {

        TextMessage message = queueSession.createTextMessage();

        message.setText(msg);

        queueSender.send(queue, message);

    }

 

    public void close() throws JMSException {

        queueSession.close();

        queueConnection.close();

    }

 

    public static void main(String[] args) {

        try {

            HelloQueue queue = new HelloQueue("ConnectionFactory",

                    "queue/testQueue");

            for (int i = 11; i < 21; i++) {

                String msg = "Hello World no. " + i;

                System.out.println("Hello Queue Publishing message: " + msg);

                queue.send(msg);

            }

            queue.close();

        } catch (Exception ex) {

            System.err.println("An exception occurred " +

"while testing HelloPublisher25: " + ex);

            ex.printStackTrace();

        }

    }

}

 

程序在控制檯輸出:

 

Hello Queue Publishing message: " Hello World no. 11

Hello Queue Publishing message: " Hello World no. 12

Hello Queue Publishing message: " Hello World no. 13

Hello Queue Publishing message: " Hello World no. 14

Hello Queue Publishing message: " Hello World no. 15

Hello Queue Publishing message: " Hello World no. 16

Hello Queue Publishing message: " Hello World no. 17

Hello Queue Publishing message: " Hello World no. 18

Hello Queue Publishing message: " Hello World no. 19

Hello Queue Publishing message: " Hello World no. 20

 

 

 

l        HelloRecvQueue.java

 

package com.jms.test;

 

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Session;

import javax.jms.TextMessage;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueSession;

import javax.jms.QueueReceiver;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

 

public class HelloRecvQueue implements MessageListener {

    QueueConnection queueConnection;

    QueueSession queueSession;

    QueueReceiver queueReceiver;

    Queue queue;

 

    public HelloRecvQueue(String factoryJNDI, String topicJNDI)

            throws JMSException, NamingException {

        Context context = new InitialContext();

        QueueConnectionFactory queueFactory =

            (QueueConnectionFactory) context.lookup(factoryJNDI);

        queueConnection = queueFactory.createQueueConnection();

        queueSession = queueConnection.createQueueSession(false,

                Session.AUTO_ACKNOWLEDGE);

        queue = (Queue) context.lookup(topicJNDI);

 

        queueReceiver = queueSession.createReceiver(queue);

        queueReceiver.setMessageListener(this);

        System.out.println("HelloReceQueue receiver to queue: " + topicJNDI);

        queueConnection.start();

    }

 

    public void onMessage(Message m) {

        try {

            String msg = ((TextMessage) m).getText();

            System.out.println("HelloReceQueue got message: " + msg);

        } catch (JMSException ex) {

            System.err.println("Could not get text message: " + ex);

            ex.printStackTrace();

        }

    }

 

    public void close() throws JMSException {

        queueSession.close();

        queueConnection.close();

    }

 

    Public ovid main(String[] args) {

    new HelloRecvQueue();

}

}

 

 

 

程序在控制檯輸出:

 

HelloReceQueue got message: Hello World no. 11

HelloReceQueue got message: Hello World no. 12

HelloReceQueue got message: Hello World no. 13

HelloReceQueue got message: Hello World no. 14

HelloReceQueue got message: Hello World no. 15

HelloReceQueue got message: Hello World no. 16

HelloReceQueue got message: Hello World no. 17

HelloReceQueue got message: Hello World no. 18

HelloReceQueue got message: Hello World no. 19

HelloReceQueue got message: Hello World no. 20

 

配置篇

下面我們來看看是JMS是在JBoss下如何配置的,首先JMS需要一個數據庫來保存其持久化的消息,幸運的是JBoss自帶有一個開源的JAVA數據庫HSQL(www.hsqldb.org

 

在這裏簡單地介紹一下這個數據庫,它支持標準的SQL語法和JDBC接口,是一個用純JAVA編寫的數據庫,其實它只有一個jar文件而已:hsqldb.jar,在%JBOSS_HOME%/server/default/lib目錄下你能找到它。

啓動這個數據庫有三種模式:Server模式、進程模式和內存模式,在Server模式下,你可以用下面的命令讓它啓動起來:

$cd %JBOSS_HOME%/server/default/lib

$ java -cp hsqldb.jar org.hsqldb.Server -database.0 mydb -dbname.0 demoDB

其中mydb是數據庫名,demoDB是數據庫別名,我們用JDBC連它是就用這個別名,用戶名是sa,密碼默認是空,我們下列語句就能創建表、插入數據了

create table employee (

  employee_id int,

  employee_name varchar(50),

  age int,

  hiredate date

)

insert into employee values(1, 'linyufa', 33, '2007-12-17')

insert into employee values(2, 'scott', 25, '2008-11-23')

insert into employee values(3, 'larry', 35, '2004-11-23')

 

想進一步瞭解HSQL的知識,網上有很多學習資料,好了,回到我們討論的JMS話題,有了這個數據庫,那我們就不必去找其他數據庫了,JMS默認是用內存模式來啓動它的,所以我們基本上不用去關心它是如何工作的。

1)   在 %JBOSS_HOME%/server/default/deploy/jms目錄下,

打開hsqldb-jdbc-state-service.xml文件,

 

<depends optional-attribute-name="ConnectionManager">

            jboss.jca:service= DataSourceBinding, name=DefaultDS

</depends>

DefaultDS這個名字就是JMS連接數據庫的數據源,可以讓其保持默認值。

 

2)   再在同一目錄打開hsqldb-jdbc2-service.xml 文件,

<depends optional-attribute-name="ConnectionManager">

jboss.jca:service=DataSourceBinding,name=DefaultDS

      </depends>

DefaultDS這個名字保持和前面一致即可,也可以讓其保持默認值。

 

3)   在同一目錄打開jbossmq-destinations-service.xml文件,找到下面的代碼段:

<mbean code="org.jboss.mq.server.jmx.Topic"

    name="jboss.mq.destination:service=Topic,name=testTopic">

    <depends optional-attribute-name="DestinationManager">

       jboss.mq:service=DestinationManager

    </depends>

    <depends optional-attribute-name="SecurityManager">

       jboss.mq:service=SecurityManager

    </depends>

    <attribute name="SecurityConf">

       <security>

       <role name="guest" read="true" write="true"/>

       <role name="publisher" read="true" write="true" create="false"/>

       <role name="durpublisher" read="true" write="true" create="true"/>

       </security>

    </attribute>

</mbean>

這是定義一個名叫testTopic的示例,如果你要定義一個新的topic,只需要複製這段代碼,改一下name屬性即可。

 

同樣找到下面這段的代碼,這是定義一個名叫testQueue的示例,如果要定義一個新的queue,複製這段代碼,改一下名字即可。

<mbean code="org.jboss.mq.server.jmx.Queue"

    name="jboss.mq.destination:service=Queue,name=testQueue">

    <depends optional-attribute-name="DestinationManager">

       jboss.mq:service=DestinationManager

    </depends>

    <depends optional-attribute-name="SecurityManager">

        jboss.mq:service=SecurityManager

    </depends>

    <attribute name="MessageCounterHistoryDayLimit">-1</attribute>

    <attribute name="SecurityConf">

      <security>

       <role name="guest" read="true" write="true"/>

       <role name="publisher" read="true" write="true" create="false"/>

       <role name="noacc" read="false" write="false" create="false"/>

      </security>

    </attribute>

</mbean>

 

 

 

4)   啓動Jboss後在控制檯看到如下輸出,即說明JMS正常啓動了

09:50:28,390 INFO  [A] Bound to JNDI name: queue/A

09:50:28,406 INFO  [B] Bound to JNDI name: queue/B

09:50:28,406 INFO  [C] Bound to JNDI name: queue/C

09:50:28,406 INFO  [D] Bound to JNDI name: queue/D

09:50:28,421 INFO  [ex] Bound to JNDI name: queue/ex

09:50:28,437 INFO  [testTopic] Bound to JNDI name: topic/testTopic

09:50:28,484 INFO  [securedTopic] Bound to JNDI name: topic/securedTopic

09:50:28,484 INFO  [testDurableTopic] Bound to JNDI name: topic/testDurableTopic

09:50:28,500 INFO  [testQueue] Bound to JNDI name: queue/testQueue

 

5)   如果是Jboss4.2或以上的版本,在啓動Jboss時必須指定 –b 0.0.0.0參數,否則本機之外的任何主機都無法連接JMS。可以修改run.batrun.sh文件,也可以在運行命令時附帶上這個參數,如下 sh run.sh –b 0.0.0.0

 

從上面介紹可以看出,在Jboss下配置JMS是非常簡單的,僅需要copy一段代碼,改個名字即可。如果在WebLogic下,你就要依次配置JMS Module, ConnectionFactory, Topic, Queue, Template,不過好在console都有嚮導,非常直觀,所以配置起來也不是什麼難事。

 

JMS編程其他注意事項

創建一個JMS Connection、查找ConnectionFactoryDestination都是需要很大的系統開銷的操作,所以我們的應用程序應避免頻繁地去做這些操作。一般情況下,我們可以把ConnectionFactoryConnection, Topic, Queue定義成類的成員變量,並在類的構造函數裏初始化他們,避免在每次接收和發送JMS消息時去做這些工作。但是因此也帶了一個問題,就是說當Connection不可用了(比如JMS Server重啓了),我們的應用程序就會開始不工作了,所以我們要有一種機制去檢測我們的Connection是否有效,如果已經斷掉,應該試圖去重新連接,並通知系統管理員。

 

JMSConnectionJDBCConnection類似,不再使用後應該關閉,不管是正常退出,還是異常退出,否則別的客戶程序可能就再也取不到連接了。Session也是如此。

 

因爲JMS工作模式是異步的,我們要意識到調用Connection.start()這個方法,系統已經啓動了一個新的線程在工作,也就是說退出了這行語句所在的方法之後,這個線程還在工作,它會不斷地去偵聽有沒有新的JMS消息,直到這個Connection被關閉或不可用。

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