<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    自由的天空

    簡單通用

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      12 隨筆 :: 6 文章 :: 9 評論 :: 0 Trackbacks
    8用JMS編程
    在本章中,我們將討論Java 消息發送服務(JMS)接口概念和MQSeries 實施,以及如
    何使用JMS 編程。我們將在消息發送編程模式的上下文中探討JMS 概念。

    8.1 什么是JMS?
    與JDBC API for databases 一樣,Java Message Services(JMS)是消息發送的標準API。
    JMS 規范(1.0.2)由Sun Microsystems 開發,IBM 和其他企業消息發送銷售商、事務處
    理銷售商以及RDBMS 銷售商都積極參與了開發過程。JMS 為Java 程序與對消息發送
    系統對象進行各種操作的消息發送系統進行互動提供了一個常見的模型。程序對消息發
    送系統對象進行的常見操作包括創建消息、發送消息、接收消息以及從企業消息發送系
    統中讀取消息。JMS 為那些用Java 開發的程序提供了一種訪問這些消息發送系統操作
    的常見方法。
    JMS 具有兩種消息發送風格,或者說它具有兩個域:
    .. 一對一或點到點模型;
    .. 發布/預訂模型。
    JMS 僅僅是種規范。每個企業消息發送系統銷售商都必須就其特定的消息發送系統提供
    實施規范的類。
    在本章中,我們將描述JMS API 的MQSeries 實施、討論JMS API 概念和MQSeries 的
    JMS 實施能力,并講解在可以利用MQSeries JMS 實施的不同情境中如何利用MQSeries
    JMS。
    為什么要使用JMS?
    JMS 標準非常重要,其原因在于:
    .. 它是第一個獲取廣泛跨行業支持的企業消息發送API;
    .. 它提供的標準消息發送概念和慣例適用于廣泛的企業消息發送系統,因而簡化了
    企業應用程序的開發;
    .. 它可以利用現有的、企業證明成功可行的消息發送系統;
    .. 它添加了完全用現有非JMS 客戶機解釋的新JMS 客戶機,從而允許您擴展現有的
    基于消息的應用程序;
    .. 它允許您可以編寫便攜性強的基于消息的商業應用程序。
    8.2 概述
    JMS 是定義JMS 客戶機如何訪問企業消息發送產品功能的一系列接口和相關語義。我
    們這里所描述的消息是指企業應用程序所使用的異步請求、報表或事件。它們既包含協
    同這些系統所需的重要信息;又包含著描述特定商業行為的精確格式化的數據。通過這
    些消息的交流,每個應用程序都能跟蹤企業的發展。
    JMS 定義了一系列常見的企業消息發送概念和功能。它最大限度地減少了Java 語言程
    序設計人員在使用企業消息發送產品前必須學會的概念集。也最大限度地加強了消息發
    送應用程序的便攜性。JMS 標準雖然提供了獨立于不同銷售商的編程接口,但是并不定
    義出通訊協議。
    JMS 模型
    JMS 定義了消息傳遞服務的一般視圖。理解該視圖,并弄清它是如何映射到底層的
    MQSeries 傳輸上的,相當重要。一般JMS 模型是建立在Sun 的javax.jms 包所定義的接
    口上的,請見圖8-1。

    圖8-1 JMS 模型
    連接
    連接提供了到底層傳輸的訪問,并被用來創建會話。在MQSeries 上下文中,連接提供
    了儲存參數,如隊列管理器名、遠程主機名(在Java 客戶連接性中)等的地方。換言之,
    MQSeries JMS 連接一般都在Java 虛擬機之外分配MQSeries 資源。連接也支持同時使用。
    連接可以提供以下好處:
    .. 包括與JMS 供應方的開放式連接。它通常代表客戶機和供應方服務端口之間的一
    個開放的TCP/IP 槽;
    .. 它的創建就是客戶機認證發生之處;
    .. 它可以指定唯一的客戶機標識符;
    .. 它提供ConnectionMetaData;
    .. 它支持可選的ExceptionListener。
    由于建立連接時完成了認證和通訊設置,因此連接相對來說是個重量級的JMS 對象。
    大多數客戶機都使用單一的連接進行消息發送。其他更先進的應用程序可能會使用幾個
    連接。JMS 并不為使用多個連接而設計原因;但是,這樣做可能有操作上的原因。
    JMS 客戶機一般創建一個連接、一個或多個會話以及許多消息生成器和使用者。當創建
    連接時,它處在停止模式,這就是說沒有消息再被送達。
    重點:連接是在停止模式中創建的。
    通常,直到設置完成前,連接都處在停止模式中。在完成時,將調用連接的start()方
    法,而消息則開始到達連接的使用者。此設置慣例可以在客戶機仍在進行設置過程中盡
    可能減少異步消息送達所帶來的任何客戶機混亂。
    連接可以立即啟動,而設置可在隨后進行。這樣做的客戶機必須在設置過程中就準備好
    處理異步消息送達。
    提示:消息生成器可以在停止連接時發送消息。
    不是直接創建連接的,而是利用連接庫建立的。庫對象可以儲存在JNDI 名稱空間中,
    從而將JMS 應用程序與供應方特定信息隔離開來。連接庫對象是利用MQSeries JMS 管
    理工具JMSAdmin 創建的。該工具使得管理員可以給JNDI 名稱空間定義MQSeries JMS
    對象的8 種類型。請參見第8.4.9 節《利用JMSAdmin 以VisualAge for Java 管理JMS JNDI
    對象》(見本書第260 頁)。
    創建連接
    客戶機利用連接庫來創建連接。要使用何種連接庫類型取決于您想要哪種類型的連接:
    .. 就PTP 連接而言,我們利用QueueConnectionFactory 或XAQueueConnectionFactory
    來獲取QueueConnection 或XAQueueConnection;
    .. 就發布/ 預訂消息發送模式而言, 我們利用TopicConnectionFactory 或
    XATopicConnectionFactory 來獲取TopicConnection 或XATopicConnection。
    為了創建連接,我們應當進行以工作:
    .. 從JNDI 名稱空間接收庫對象
    JNDI API 向以Java 編寫的應用程序提供了命名和目錄功能。它是利用Java 的對象
    模型專門為Java 設計的。利用JNDI,Java 應用程序可以儲存并接收任何類型的命
    名為Java 的對象。另外,JNDI 提供進行標準目錄操作的方法,如將屬性與對象相
    關聯并利用對象屬性查找對象等。
    在此常見的API 之后,可以無縫地插入不同的命名和目錄服務供應方。這使得Java
    應用程序可以通過各種各樣的命名和目錄服務來利用信息,如LDAP、NDS、DNS
    和NIS(YP)等,也使得Java 應用程序可以與傳統應用程序和系統并存。
    在JNDI 中,所有的命名和目錄操作都是根據上下文進行的。沒有絕對的根。因此,
    JNDI 定義了初始上下文,它是命名和目錄操作名解析的起始點。一旦有了初始上
    下文,您就可以利用它來查看其他上下文和對象。
    .. 為了從JNDI 名稱空間接收對象,必須按照下面這段代碼所顯示的那樣設置初始上
    下文:
    import javax.jms.*
    import javax.naming.*;
    import javax.naming.directory.*;
    java.util.Hashtable ;
    Hashtable env =new Hashtable();
    env.put(Context.INITIAL_CCONTEXT_FACTORY,icf);
    env.put(Context.PROVIDER_URL,url);
    Context ctx =new InitialDirContext(env);
    Icf 為初始上下文定義了庫類,url 則定義了隨上下文而變的URL。
    .. 一旦獲取了初始上下文,我們就可以利用lookup()方法來從名稱空間接收對象。
    下面這段代碼從基于LDAP 的名稱空間接收QueueConnectionFactory 名firstQCF;
    QueueConnectionFactory qFactory ;
    queueFactory =(QueueConnectionFactory)ctx.lookup(“cn=firstQCF ”);
    .. 利用庫對象來獲取連接。
    241
    利用庫對象的createQueueConnection()方法來創建連接,請參見如下的例子:
    QueueConnection connection ;
    connection =qFactory.createQueueConnection();
    .. 啟動連接
    JMS 規范定義指出,應當在“停止”狀態下創建連接。在您可以利用連接發送消息
    之前,必須顯式啟動連接。
    我們利用start()方法啟動連接,請參見如下的例子:
    connection.start();
    會話
    為生成和使用消息提供上下文,包括用來創建消息生成器和消息使用者的方法。
    JMS 會話是生成和使用消息的單線程上下文。盡管它可以在Java 虛擬機之外分配供應
    方資源,但我們還是將其看作輕量級JMS 對象。
    我們可以分別利用連接對象的createQueueSession()或createTopicSession()方法來創
    建會話。
    創建會話方法包括兩個參數:
    1. 可決定會話是否進行事務處理的boolean。
    在事務處理的會話中,全部發送、或者全部接收作為一個單位的一組消息。
    在非事務處理會話中,分別發送或接收消息。
    2. 定義識別模式的參數。
    請參見如下的例子:
    session =connection.createQueueSession(false ,Session.AUTO_ACKNOWLEDGE);
    這是用AUTO_ACKNOWLEDGE 來創建非事務處理會話的最簡單的情況。連接是
    線程安全的,但會話和由會話創建的對象不是線程安全的。我們建議多線程應用程
    序應當對每個線程都使用不同的會話。
    會話有以下幾種用途:
    .. 它是消息生成器和使用者的庫;
    .. 它提供了供應方優化的消息庫;
    .. 它既支持單一事務處理,又支持一系列將跨越生成器和使用者的庫結合到原子單
    位的事務處理;
    .. 會話為它使用和生成的消息定義了連續序列;會話保存了它使用的消息,直到識
    別該消息;
    .. 會話串行化注冊到消息使用者的消息偵聽器。
    會話可以創建并服務于多個消息生成器和使用者。
    一種典型的用法就是在消息到達前一直在同步消息使用者上保持線程塊。然后線程可以
    使用一個或更多的會話消息生成器。
    如果一個客戶機希望在其他客戶機使用消息時具備一個生成消息的線程,那么該客戶機
    就應當為生成線程使用另外的會話。
    一旦啟動了連接,任何具有偵聽器或注冊消息偵聽器的會話就會被賦予送達消息的控制
    線程。客戶機代碼從另一個控制線程利用會話或任何構成會話的對象都是錯誤的。唯一
    的例外就是使用會話或連接關閉方法。
    大多數客戶機將它們的庫自然地分成會話應當是比較容易的。該模型允許客戶機簡單啟
    動并隨著并行操作需要的增加而逐漸增加消息線程的復雜度。
    關閉方法是當另一個線程正在執行某個其他會話方法時唯一可以調用的會話方法。
    我們可以選擇地指定會話為事務處理會話。每個事務處理會話都支持單一系列的事務處
    理。每個事務處理會將一系列消息發送和一系列消息接收歸組到原子庫單元中。事實上,
    事務處理將會話的輸入消息流和輸出消息流組織到原子單位集中。當提交事務處理時,
    會確認輸入的原子單位,同時發送與其相關聯的輸出原子單位。如果已經進行了事務處
    理回退,那么其發送的消息則被毀壞,會話的輸入也被自動恢復。
    事務處理輸入和輸出單位的內容就是會話的當前事務處理中所生成和使用的那些消息。
    我們可以利用會話的提交或回退方法完成事務處理。會話的當前事務處理的完成將自動
    開始下一個事務處理。其結果就是,事務處理會話總是具有一個當前事務處理,且其庫
    就在當前事務處理中完成。
    消息生成器
    JMS 客戶機利用消息生成器發送消息到特定的目的地。我們通過傳遞目的地到會話對象
    提供的創建消息生成器方法,從而創建消息生成器。
    在點到點消息發送中,這將是利用QueueSession 對象上的createSender 方法所創建的
    QueueSender。QueueSender 通常是為特定隊列創建的,因此所有利用該發送器發送的消
    息都會被發送到同樣的目的地。我們利用隊列對象指定目的地。隊列對象即可以在運行
    時間中創建,也可以在JNDI 名稱空間中構造和儲存。請參見如下的例子:
    Queue ioQueue ;
    ioQueue = (Queue).ctx.lookup(qLookUp) ;
    sender = session.createSender(ioQueue);
    在發布/預訂消息發送中,這將是在TopicSession 對象上利用createPublisher 方法創建
    的TopicPublisher。
    通常,Topic 是在創建TopicPublisher 時指定的。在這種情況下,嘗試去使用方法,該方
    法為未確認的TopicPublisher,將生成UnsupportedOperationException。
    請參見如下的例子:
    Topic topic ;
    topic = (Topic)ctx.lookup( “cn=first.topic”) ;
    TopicPublisher pub = session.createPublisher(topic);
    客戶機也可以選擇不提供目的地而創建消息生成器。在這種情況下,目的地必須輸入每
    個發送操作。這種風格的消息生成器一般用來根據請求的replyTo 目的地向請求發送回
    復。
    客戶機可以通過消息生成器為發送的消息指定默認的送達模式、優先級和使用期限。它
    也可以為每條消息指定送達模式、優先級和使用期限。
    244
    客戶機可以為它發送的每條消息指定單位為毫秒的使用期限值。這個值定義了消息到期
    時間,也就是消息使用期限的和以及消息發送的GMT 時間(對事務處理發送而言,這
    是指客戶機發送消息的時間而不是提交事務處理的時間)。
    發送消息
    消息是用消息生成器發送的。因此在點到點(PTP)模型中發送消息時,您應當使用
    QueueSender 對象,而在發布/預訂模型中,您則應當使用TopicPublisher 對象。
    在PTP 模型中,應使用QueueSender 的send()方法發送消息。請參見如下的例子:
    outmessage = session.createTextMessage();
    outmessage.setText(“Sample Message “) ;
    sender.send(outMessage);
    在發布/預訂模型中,應使用TopicPublisher 對象的發布方法來發布消息。請參見如下
    的例子:
    pub.publish(outMessage);
    消息使用者
    消息使用者是用來接收消息的。MessageConsumer 接口是所有消息使用者的父級接口。
    在PTP 模型中,這將是QueueReceiver。在發布/預訂模型中,這將是TopicSubscriber。
    我們可以用消息選擇器來創建消息使用者,消息選擇器允許客戶機根據消息選擇器指定
    的標準選擇消息子集。欲了解詳細信息,請參見第8.7 節《消息選擇器》(見本書第289
    頁)。
    消息使用者客戶機可以同步接收消息,也可以讓消息在到達時異步送達。客戶機可以利
    用其接收方法之一從消息使用者請求下一條消息。接收有幾種不同的形式,允許客戶機
    登記或等待下一條消息。
    客戶機可以向消息使用者注冊MessageListener 對象。當消息到達消息使用者時,它是通
    過調用MessageListeners onMessage 方法來送達消息的。欲了解更多信息,請參見第8.6
    節《異步處理》(見本書第285 頁)。
    245
    在PTP 模型中,QueueReceiver 是利用QueueSession 對象上的createReceiver()方法創
    建的。該方法采用的是從何處接收消息定義的Queue 參數。請參見如下的例子:
    QueueReceiver queueReceiver = session.createReceiver(ioQueue) ;
    在發布/預訂模型中,TopicSubscriber 對象是利用TopicSession 對象的createSubscriber
    ()方法創建的。請參見如下的例子:
    TopicSubscriber sub = session.createSubscriber(topic);
    接收消息
    消息是用消息使用者接收的。在PTP 消息發送中,應當用QueueReceiver 對象來接收消
    息,而在發布/預訂消息發送中,則應當用TopicSubscriber 對象來接收消息。
    在PTP 模型中,您可以利用QueueReceiver 對象的接收方法來接收消息。請參見如下的
    例子:
    Message inMessage = queueReceiver.receive(800) ;
    指定的參數是以毫秒為單位的超時。此方法發出調用,以接收指定超時間隔內到達的下
    一條消息。
    在發布/預訂模型中,我們利用TopicSubscriber 的receive()方法來接收預訂。請參見
    如下的例子:
    Message inMsg = sub.receive() ;
    這段代碼執行了帶有等待的獲取方法。
    重點:請注意,連接是線程安全的,但會話、消息生成器和消息使用者則不是。我們建
    議的做法是對每個應用程序線程使用一個會話。
    在MQSeries 條款中,連接為臨時隊列提供了作用域。它也提供了地方,可以用來儲存
    參數,該參數控制如何連接到MQSeries。舉例來說,這些參數就是隊列管理器名和遠
    程主機名(如果您使用MQSeries Java 客戶機連接的話)。會話包含HCONN,因此定義
    了事務處理作用域。
    消息生成器和消息使用者包含HOBJ,它定義了向其寫入或從其讀取的特定隊列。請注
    意,正常的MQSeries 規則是適用的。在任何給定時間上,每個HCONN 只能進行一個
    單一的操作。因此,不能同時調用消息生成器或與會話相關的消息使用者。
    這與JMS 每個會話只有單一線程的限制是一致的。放置方法可以使用遠程隊列,但獲
    取方法只能適用于本地隊列管理器上的隊列。一般JMS 接口是進一步劃分為更具體的
    版本子集,該子集為點到點以及發布/預訂行為。點到點版本如下:
    .. QueueConnection QueueSession QueueSender QueueReceiver
    JMS 的關鍵理念就是,它編寫的應用程序可以只在javax.jms 中接口引用。
    我們強烈建議您這么做。所有各銷售商特有的信息都包含在以下實施中:
    .. QueueConnectionFactor TopicConnectionFactory
    - Queue
    - Topic
    以上這些稱作“管理對象”,即可以利用銷售商提供的管理工具構造、且能被儲存在JNDI
    名稱空間中的對象。JMS 應用程序可以從名稱空間接收并使用這些對象,而不必知道由
    哪個銷售商進行實施。MQSeries classes for Java Message Service 由許多Java 類和接口構
    成,這些類和接口是以Sun 的接口和類javax.jms 包為基礎的。
    應當用下面所列的Sun 接口和類編寫客戶機,我們將在下面各節中詳細描述這些接口和
    類。可實施Sun 接口和類MQSeries 對象的名稱具有“MQ”作為前綴(如果對象描述中
    沒有做出其它規定的話)。描述包括有關MQSeries 對象與標準JMS 定義存在任何偏差
    的細節。
    事務處理
    會話是在客戶機和消息發送系統之間的連接上一系列被發送和接收的消息。當創建會話
    時,它可以是非事務處理的(默認)也可以是事務處理的。事務處理會話保證一組消息
    要么都被發送接收,要么都不被發送接收。非事務處理會話意味著消息被分別發送和接
    收。在線購物就是事務處理會話的一個實例。客戶打開訂單(開始事務處理)。客戶選
    擇的每項商品都是一條在訂單中添加商品的消息。客戶關閉訂單(結束事務處理)。如
    果發送器提交了事務處理,那么將發送組中所有的消息。如果發送器回退事務處理的話,
    那么將不訂購任何商品項目。
    8.3 JMS消息
    JMS 提供不同的消息類型。每種類型都包括有關其內容的某些信息。
    JMS 中定義的消息類型如下:
    .. BytesMessage
    .. MapMessage
    .. ObjectMessage
    .. StreamMessage
    .. TextMessage
    JMS 消息由以下三部分構成:
    .. 標題
    標題字段包括供應方用于路由和確認消息的信息,以及客戶機可以利用的信息。
    .. 屬性
    除標題中的字段外,JMS 消息還為添加可選的標題字段到消息提供功能。這些屬性
    可以分為:
    - 應用程序特定屬性,客戶機為處理消息用這些屬性添加進程特定信息;
    - 標準屬性,即JMS 特定屬性;
    - 供應方特定屬性,原始客戶機要求這些屬性。
    .. 主體
    這就是消息數據部分的所在。JMS 提供不同類型的消息主體,包括大部分當前正被
    使用的消息發送風格。
    8.3.1 映射JMS消息到MQSeries消息上
    MQSeries 消息有三個組成部分:
    .. MQSeries 消息描述器(MQMD);
    .. MQSeries MQRFH2 標題;
    .. 消息主體。
    MQRFH2 標題是可選的。MQRFH2 標題是具有固定部分和可變標題部分的可擴展的標
    題。固定部分以標準MQSeries 標題模式為模型。MQRFH2 標題既可以攜帶與消息內容
    相關聯的JMS 特定數據,又可以攜帶不直接與JMS 相關聯的其他信息。
    我們用兩種方法將JMS 消息翻譯或轉化為MQSeries 消息。
    .. 映射
    映射是將JMS 消息標題和消息屬性翻譯到有相應MQMD 字段的相應MQMD 值。
    .. 拷貝
    如果JMS 消息標題和消息屬性值不具有相應的MQMD 字段的話,JMS 標題字段或
    屬性將被傳遞,并可能作為MQRFH2 標題中的一個字段被轉化。
    是否包括MQRFH2 標題是可選的。在發送消息中,JMS 目的地類的標記決定是否包括
    它。該標記可以在定義JMS 管理對象時用JMSAdmin 工具來設定。管理員可以設置
    MQSeries 目的地的TargetClient 值為JMSC.MQJMS_CLIENT_NONJMS_MQ,從而顯示
    出JMS 客戶機正與非JMS 客戶機通訊。由于MQRFH2 標題攜帶著JMS 特定信息,因
    此如果發送器知道接收客戶機是JMS 客戶的話,您就應當包括它。如果接收器不是JMS
    客戶機,那么就應當省略MQRFH2 標題。
    處理JMS 消息類型
    在本節中,我們將利用發貨跟蹤ID(它作為JMS 客戶機的一條消息被發送)講解可以
    如何使用不同的JMS 消息類型。
    使用TextMessage 類
    消息中的信息可以作為人類可以閱讀的文本字符串發送,客戶機也可以讀取并處理或者
    顯示該字符串。
    我們可以如下將跟蹤ID 作為TextMessage 對象中的字符串發送:
    String trackingId ;
    TextMessage message;
    message =session.createTextMessage();
    message.SetText(trackingId);
    使用BytesMessage 類
    在BytesMessage 中,信息是以二進制格式發送的。消息中的信息可以作為字節數組構件。
    可以如下準備這樣的消息:
    byte [] trackingId ;;
    BytesMessage message ;
    message =session.createBytesMessage();
    message.writeBytes(trackingId);
    使用映射消息
    在映射消息中,信息可以作為名值對發送。這樣,消息本身可以包括消息所儲存數據的
    元數據。
    在我們所用的例子中,發送消息請求trackingId 上的信息,名(元數據)可以是trackingId,
    實際值(比如說AMX100000)將是名值對的值。
    消息可以如下構造:
    String attributeName =“trackingId ”;
    String attributeValue =“AMX100000 ”
    MapMessage message;
    message =session.createMapMessage();
    message.setString(attributeName,attributeValue);
    提示:如果值部分是較長的數據類型的話,那么您可以使用消息setLong 方法。請根據
    您處理的數據類型選擇合適的方法。
    使用流消息
    在流消息中,與映射消息相似,消息可以由順序寫入的各種字段構成,每個字段都有其
    自己原始的類型。在映射消息中,客戶機可以設置映射中任意數量的字段,處理客戶機
    則可以讀取特定的字段而不必處理整個映射。但是,在流消息中,即便處理客戶機僅對
    流消息中的字段子集感興趣,客戶機仍必須讀取消息中的每個字段(再摒棄它不感興趣
    的字段)。此二者的另一個重要差別就是,在映射消息中,字段順序并不重要,但在流
    消息中,字段是以寫入順序讀取的。
    流消息可以如下構造:
    String attributeName =“trackingId ” ;;
    String attributeValue =“AMX100000 ” ;;
    StreamMessage message;
    session.createStreamMessage();
    message.writeString(attributeName);
    message.writeString(attributeValue);
    使用對象消息
    對象消息可被用來將Java 對象作為一條消息傳遞,該消息就是接收客戶機可以在對象中
    利用方法提取數據的消息。在下面的例子中,我們使用的是跟蹤對象:
    p
    ublic class TrackingObject {
    private String attributeName ;
    private String attributeValue ;
    public void setAttributeName (String name ){
    attributeName =name ;
    }
    public void setAttributeValue(String value){
    attributeValue =value ;
    }
    public String getAttributeName(){
    return attributeName;
    }
    public String getAttributeValue(){
    return attributeValue ;
    }
    }
    Using the above tracking object we can sent the tracking information as a
    tracking object.(利用以上跟蹤對象,我們能發送作為跟蹤對象的跟蹤消息)
    We can construct such a message as:(我們能構造如下的消息)
    String attributeName =“trackingId ” ;;
    String attributeValue =“ AMX100000” ;
    TrackingObject trakingObject =new TrackingObject();
    ObjectMessage =message ;
    trackingObject.setAttributeName(attributeName);
    trackingObject.setAttributeValue(attributeValue);
    message =session.createObjectMessage();
    message.setObject(trackingObject);
    在接收方,客戶機可以使用跟蹤對象的獲取方法來提取數據。
    消息識別
    如果客戶機指定JMS 使用者的消息應被顯式識別的話,那么JMS 消息也支持使用識別
    方法。如果客戶機使用自動識別的話,那么將忽略識別調用。
    消息識別有三種類型。消息識別的類型是在會話創建時指定的。這些不同的類型如下:
    .. AUTO_ACKNOWLEDGE
    在AUTO_ACKNOWLEDGE 模式中,當消息成功從調用返回到接收器,或消息使
    用者注冊的處理消息的消息偵聽器成功返回時,消息會話將自動識別消息。
    Session session =queueConnection.createQueueSession(false,
    Session.AUTO_ACKNOWLEDGE);
    .. CLIENT_ACKNOWLEDGE
    利用CLIENT_ACKNOWLEDGE 模式,客戶機通過調用消息上的識別方法顯式并
    確認消息。
    Session session =queueConnection.createQueueSession(false,
    Session.CLIENT_ACKNOWLEDGE);
    Then once the message is processed,the client can issue(然后一旦處理完消息,客戶機就能發行)
    message.acknowledge();
    method to acknowledge the message.(方法以確認該消息)
    當使用CLINET_ACKNOWLEDGE 模式時,我們在處理消息過程中必須注意避免
    大量未識別消息的積累,未識別消息的積累可能導致資源耗盡,帶來失敗。
    .. DUPS_OK_ACKNOWLEDGE
    DUPS_OK_ACKNOWLEDGE 模式命令會話遲鈍地確認消息送達。如果JMS 失敗
    的話,其結果就可能是重復消息發送。允許處理重復消息的使用者應當使用這種模
    式。在客戶機允許重復消息的情況下,利用這種模式可以獲取一些效能改善,因為
    會話在避免重復消息時的開銷較小。
    8.3.2 JMS補充特性
    JMS 還包括其他一些特性:
    .. 異步消息送達
    - 使用消息偵聽器概念;
    - 使用基于事件的模型,它在事先設定的事件上觸發指定的函數。
    JMS 客戶機可以注冊偵聽器對象,它可以實施具有消息使用者(消息接收器)的
    MessageListener 接口。當注冊使用者的消息到達時,我們可以調用listeners
    onMessage 方法讓消息對消息使用者可用。
    .. 消息選擇器
    - 基于內容的特定消息接收
    - 使用基于SQL92 的查詢函數
    JMS 消息具有向JMS 消息標題(在消息實際主體外)提供用戶定義元數據的功能。JMS
    程序可以利用這一功能根據選擇標準選擇消息子集,換言之,JMS 客戶機可以僅選擇那
    些自己感興趣的消息。
    8.4 MQSeries JMS實施
    用MQSeries 實施JMS 的重點如下:
    .. 支持的平臺:AIX, HP-UX, Windows NT, Solaris 和 Linux
    .. 由包括關鍵功能的JAR 文件構成
    - com.ibm.mq.jms.jar
    - com.ibm.mq.jar
    .. 定義管理對象到JNDI 名稱空間的管理工具:
    - JMSAdmin
    .. 作為產品延伸可以通過網絡下載獲取
    .. MQSeries classes for Java 和JMS with MQSeries V5.2
    8.4.1 MQSeries JMS的安裝
    為了使JMS 支持MQSeries,您必須安裝并實施JMS 接口的Java 類。JMS classes for
    MQSeries 可以從下述IBM 網站的MA88 SupportPac 下載獲取:
    http://www-3.ibm.com/software/ts/mqseries/txppacs/
    此SupportPac 是免費的。您可以根據支持的平臺下載合適的版本,并按照隨SupportPac
    提供的安裝說明進行安裝。
    重點:當您在安裝JMS SupportPac 時,位于MQSeries 安裝的Java 次級目錄中的所有文
    件都會在安裝過程中備份,新文件拷貝自SupportPac。如果在您的上下文中已經安裝了
    AMI 支持,那么您可能需要重新安裝AMI SupportPac。
    一旦您已安裝了JMS SupportPac,為了用JMS 運行發布/預訂應用程序,您還需要運行
    稱作MQJMS_PSQ.mqsc 的MQSC 腳本,它位于MQSeries 安裝目錄下的java\bin 次級目
    錄中。為了在默認的隊列管理器上運行腳本,請從操作系統命令行窗口中運行以下命令:
    runmqsc <“C:\Program Files \IBM \MQSeries \java \bin \MQJMS_PSQ.mqsc ”
    這里,我們假定C:\Program Files \IBM \MQSeries \就是MQSeries 的安裝目錄。
    8.4.2 JMS管理對象——JNDI和JMSAdmin
    目錄服務包括命名功能,在消息發送語句中提供包括各種實體(機器名、服務、用戶以
    及MueueManagers, Queues, Topics 等供應方特定對象)安排和確認的抽象層次名稱空間。
    這就使得我們可以利用邏輯名稱空間,簡化了網絡中的對象發現和識別。Java 命名和目
    錄接口(JNDI)API 實施向以Java 開發的程序提供了目錄和命名功能。這是的Java 程
    序可以從JNDI 名稱空間發現并接收任何類型的對象。
    JMS 管理對象是JMS 應用程序儲存并從JNDI 名稱空間接收的對象。JMS 管理對象通常
    由管理員創建。JMS 管理對象包含底層消息發送服務供應方信息的配置信息。在這節中,
    我們將就以MQSeries 開發和應用JMS 應用程序來討論這些對象的定義、管理和使用。
    重點:在程序樣例中,我們將使用作為JNDI 服務器的WebSphere 應用程序服務器所提
    供的持久名服務器。我們是利用VisualAge for Java 企業版和Websphere application Server
    來開發程序樣例的。
    8.4.3 JMSAdmin工具
    管理工具JMSAdmin 使得管理員可以定義MQSeries JMS 對象,并將其儲存在JNDI 名
    稱空間中。JMS 客戶機可以利用JNDI 接口從名稱空間接收這些管理對象。該工具也允
    許管理員操縱JNDI 中的目錄名稱空間子上下文。
    您可以用JMSAdmin 工具管理以下8 個管理對象:
    .. MQQueueConnectionFactory
    .. MQTopicConnectionFactory
    .. MQQueue
    .. MQTopic
    .. MQXAQueueConnectionFactory
    .. MQXATopicConnectionFactory
    .. JMSWrapXAQueueConnectionFactory
    .. JMSWrapXATopicConnectionFactory
    提示: JMSWrapXAQueueConnectionFactory 和JMSWrapTopicConnectionFactory 是
    WebSphere 特有的類,包含在com.ibm.ejs.jms.mg 包中。
    8.4.4 調用管理工具
    管理工具具有命令行接口。您可以互動地利用此接口,也可以用它來啟動批處理進程。
    互動模式提供命令提示符,您可以在此輸入管理命令。在批處理模式中,啟動工具的命
    令包括包含管理命令腳本的文件名。
    為了在互動模式下啟動該工具,請輸入以下命令:
    JMSAdmin [-t ] [-v ] [-cfg config_filename ]
    在這里:
    .. -t 啟動跟蹤(默認情況下為跟蹤關閉)
    .. -v 生成詳細輸出(默認情況下為簡潔輸出)
    .. -cfg config_filename 為備用配置文件名。
    8.4.5 JMSAdnub工具配置
    JMSAdmin 工具在其中的以下參數使用配置文件:
    .. INITIAL_CONTEXT_FACTORY
    這顯示出工具使用的服務供應方。現在該屬性有3 個被支持的值:
    - com.sun.jndi.ldap.LdapCtxFactory
    當您使用LDAP 服務器作為JNDI 服務器時,您需要使用此類名。(在我們的測
    試中,我們將使用IBM Secureway Server 3.2.1。)
    - com.sun.jndi.fscontext.RefFSContextFactory
    當您在使用文件系統儲存JNDI 對象時,應當使用此類名。
    - com.ibm.ejs.ns.jndi.CNInitialContextFactory
    當您在使用Websphere 的持久名服務器時,您應當使用此類名。
    .. PROVIDER_URL
    這顯示出會話初始上下文的URL,即該工具執行的所有JNDI 操作的根。現在支持
    該屬性的有3 種形式:
    - ldap://hostname/contextname (針對LDAP)
    - file:[drive:]/pathname (針對文件系統上下文)
    該工具不會創建路徑指定的目錄。您應當在使用JMSAdmin 工具前確保目錄存
    在。
    - iiop://hostname[:port] /[?TargetContext=ctx] (針對WebSphere Persistent
    Name Server)
    .. SECURITY_AUTHENTICATION
    這顯示出JNDI 是否傳遞安全證明到您的服務供應方。只有在使用LDAP 服務供應
    方時才會用到該參數。該參數現在可以具有以下三個值之一:
    - None(匿名識別)
    - Simple(簡單識別)
    - CRAM-MD5(CRAM-MD5 識別機制)
    以上的值指定在一個配置文件中,您可以在以-cfg 參數調用JMSAdmin 工具時指定配
    置文件。稱作jmsadmin.config 的配置文件樣例位于MQSeriesInstalldirectory\java\bin,您
    可以編輯它或使用它,以適應上下文的屬性值來創建配置文件。
    8.4.6 以持久名服務器使用JMSAdmin
    編輯隨安裝帶來的JMSAdmin.config 文件(您可以在MQSeriesInstalldirectory\java\bin 下
    找到該文件),指示JMSAdmin 工具應當使用持久名服務器,并編輯PROVIDER_URL
    屬性值,以指向持久名服務器。而后在另一個文件夾中保存文件,例如C:\temp。
    在JMSAdmin.config 文件中,我們提供如下值:
    .. INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory
    該值對VisualAge for Java 企業版和WebSphere 應用程序服務器提供的持久名服務
    器有效。對另一個JNDI 服務器而言,INITIAL_CONTEXT_FACTORY 變量必須隨
    配套文檔提供。
    .. PROVIDER_URL=iiop://hostname/
    在此,hostname 即持久名服務器運行的機器名。當使用IIOP 協議時,默認端口為
    900,不必提及。如果您改變持久名服務器的默認端口(默認端口為900)的話,那
    么您必須在PROVIDER_URL 變量中指示端口,例如:iiop://hostname:901/(這
    里假定您將默認端口900 改為901 端口)。
    利用-cfg 參數調用JMSAdmin 工具,并給出您在編輯后保存JMSAdmin.config 文件的
    路徑。
    8.4.7 以VisualAge for Java使用持久名服務器
    持久名服務器的數據庫應當可以利用JDBC 從VisualAge for Java 訪問到。如果是第一次
    設置持久名服務器的話,您將需要創建數據庫(我們利用UDB7.1 作為數據庫服務器)。
    我們創建了稱作jndi 的數據庫。為了讓持久名服務器利用JDBC 訪問數據庫,VisualAge
    for Java 庫空間類路徑也應當包括Db2UdbInstallDirectory\java\db2java.zip。
    從VisualAge for Java 啟動持久名服務器
    .. 從VisualAge for Java 菜單欄選擇Workspace - > Tools - >Websphere Test
    Environment(見圖8-2)。
    圖8-2 從VisualAge for Java 步驟一啟動持久名服務器
    .. 在左手邊的窗格中選擇持久名服務器并輸入參數以連接到持久名服務器的配置數
    據庫,請看圖8-3;
    圖8-3 持久名服務器配置畫面
    重點:在默認情況下,持久名服務器使用端口號900。如果您已經指定了不同的端口的
    話,那么為JNDI lookup 使用名服務器的程序就應當包括PROVIDER_URL 參數中的端
    口號。
    .. 點擊Start Name Server 按鈕啟動持久名服務器。
    8.4.8 為配合使用JMS配置VisualAge for Java
    設置VisualAge for Java 與JMSAdmin 配合庫或開發JMS 應用程序的相關步驟如下:
    .. 校驗IBM 企業版庫和IBM WebSphere 監測上下文已加載入庫空間;
    .. 調入以下JAR 文件到項目中。可以在MQInstallationDirectory\Java 下找到這些JAR
    文件。我們在VisualAge for Java 中已創建了名為JMSTest 的新項目,該項目將用
    于以下的實例。
    - com.ibm.mq.jar
    - com.ibm.mqbind.jar
    - com.ibm.mqjms.jar
    - com.ibm.mq.iiop.jar
    - jms.jar
    - jndi.jar
    - ldap.jar
    - fscontext.jar
    - providerutil.jar
    .. 添加MQSeriesInstallDirectory\java\lib 目錄到VisualAge for Java 庫空間類路徑。我
    們可以通過選擇Window -> Options->Resources -->Edit 和添加目錄來實現
    這一目的(請參見圖8-4)。
    圖8-4 設置VisualAge for Java 庫空間類路徑
    .. 如果您希望在訪問隊列管理器時使用綁定模式的話,那么路徑系統環境變量就應
    當包括MQSeriesInstallDirectory\Java\bin 目錄。該目錄包括mqjbnd02.dll,在使用
    綁定模式時要求具有該文件。
    8.4.9 用JMSAdmin配合VisualAge for Java管理JMS JNDI對象
    在本節中,我們將講解如何定義和管理用MQSeries JMS 管理工具JMSAdmin 配合
    VisualAge for Java 實施JMS 時所需的JNDI 對象。
    我們將在本章下面的編程樣例中介紹如何使用工具處理對象,既包括點到點模式,又包
    括發布/預訂消息發送模式。
    被使用的MQSeries 對象
    表8-1 列出了程序樣例中用到的MQSeries 對象。
    表8-1 程序樣例中用到的MQSeries 對象
    對象名 描述
    SAMPLE.QMGR1 程序樣例中將要使用的隊列管理器
    PTP.QUEUE.LOCAL 點到點樣例中使用的隊列
    PTP.REPLY.QUEUE.LOCAL 請求/回復發送回復消息所用的隊列
    JMS.SVR.CHNL 客戶機連接所用的服務器連接通道
    SYSTEM.JMS.ADMIN.QUEUE JMS 發布/預訂管理隊列
    SYSTEM.JMS.PS.STATUS.QUEUE JMS 發布/預訂狀態隊列
    SYSTEM.JMS.REPORT.QUEUE JMS 發布/預訂報表隊列
    SYSTEM.JMS.MODEL.QUEUE JMS 發布/預訂預訂器模型隊列。(預訂器使
    用該模型隊列為預訂創建永久隊列)
    SYSTEM.JMS.ND.SUBSCRIBER.QUEUE JMS 發布/預訂默認非可持續共享隊列(非可
    持續預訂器使用的默認共享隊列)
    SYSTEM.JMS.ND.CC.SUBSCRIBER.QUEUE JMS 發布/預訂ConnectionConsumer 功能的默
    認非可持續共享隊列
    SYSTEM.JMS.D.SUBSCRIBER.QUEUE JMS 發布/預訂默認可持續共享隊列(可持續
    預訂器使用的默認共享隊列)
    SYSTEM.JMS.D.CC.SUBSCRIBER.QUEUE JMS 發布/預訂ConnectionConsumer 功能的默
    認可持續共享隊列
    261
    8.4.10 定義JMS管理對象
    首先,我們要實施點到點程序樣例使用的管理對象。我們將用作為JNDI 名服務器的持
    久名服務器庫,并從VisualAge for Java 調用JMSAdmin 工具。您應當設置VisualAge 來
    用JMS 庫,持久名服務器應當以第8.4.7 節《以VisualAge for Java 使用持久名服務器》
    (見本書第256 頁)和第8.4.8 節《為配合使用JMS 配置VisualAge for Java》(見本書第
    258 頁)介紹的方法配置和啟動。
    從VisualAge for Java 調用JMSAdmin 工具
    .. 更新JMSAdmin.config 文件指示JMSAdmin 將編輯初始上下文庫屬性值以使用持
    久名服務器。
    INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory
    提示:在LDAP 服務器中,它將是com.sun.indi.ldap.LdapCtxFactory,而在文件系
    統上下文中,值將是com.sun.jndi.fscontext.RefFSContextFactory。
    編輯PROVIDER_URL,以指向JNDI 名服務器。在這種情況下,我們是在名為ITSOG
    的服務器上運行持久名服務器,因此它將是:
    PROVIDER_URL=iiop://itsog/
    .. 拷貝上述您正在處理項目(我們正在使用名為JMSTest 的項目)的項目資源中的
    JMSAdmin.config 文件。我們可以通過以下方法從VisualAge for Java 實現此目的:
    - 在資源標簽上右鍵點擊項目,再點擊Add --> Resources,請看圖8-5。
    262
    圖8-5 向VisualAge 項目添加資源(第一步)
    .. 選擇JMSAdmin.config 文件所在的目錄,點擊OK 按鈕(見圖8-6)。
    263
    圖8-6 選擇資源目錄
    .. 在圖8-7 所示的添加資源窗口選擇JMSAdmin.config 文件并點擊OK。
    264
    圖8-7 添加JMSAdmin 配置文件資源
    .. 擴展您的項目,并定位JMSAdmin 類(它在com.ibm.mq.jms.admin 包中)。右鍵點
    擊JMSAdmin 類,再選擇Properties(見圖8-8)。
    265
    圖8-8 為JMSAdmin 設置類路徑(步驟一)
    .. 在隨后生成的JMSAdmin 屬性窗口中(見圖8-8),選擇Classpath 標簽,而后點
    擊Edit 并選擇IBM 企業擴展庫和IBM WebSphere 測試上下文,再點擊OK。
    266
    圖8-9 JMSAdmin 的類路徑
    JMSAdmin 設置至此完成。現在,我們就可以運行了。選中JMSAdmin 類,并且點擊
    Run 按鈕來運行工具。啟動成功時控制臺將如圖8-10 所示。
    267
    圖8-10 JMSAdmin 控制臺
    重點:如果您啟動JMSAdmin 工具遇到了問題,那么請校驗類路徑設置是正確的,且持
    久名服務器已經啟動。
    現在,我們就可以在JNDI 創建JMS 管理對象了。
    1. 創建上下文。我們使用JMSAdmin 命令DEFINE CONTEXT(context)名來為稱作
    ptpCtx 的上下文(它將用于點到點程序樣例中)創建上下文。
    在控制臺標準輸入區(見第268 頁上的圖8-11),輸入命令:(283)
    def ctx(ptpCtx)
    268
    圖8-11 使用JMSAdmin 工具創建JNDI 上下文
    為了顯示您剛剛定義的上下文,請使用dis ctx 命令。在顯示上下文時,您應當可以看到
    您剛剛創建的上下文。請見圖8-12。
    269
    圖8-12 JMS admin 工具中的上下文
    2. 利用以下命令改變到您剛剛創建的上下文:
    chg ctx(ptpCtx)
    3. 用下面的命令創建名為ptpQcf 的QueueConnection 庫:
    def qcf(ptpQcf) transport(CLIENT)+
    channel(JMS.SRV.CHNL) qmanager(SAMPLE.QMGR1) host(ITSOG)
    4. 如下創建名為ptpQcf 的隊列對象:
    def q(ptpQueue) queue(PTP.QUEUE.LOCAL)+
    qmanager(SAMPLE.QMGR1)
    您可以利用dis ctx 名校驗在當前上下文下創建的對象。您應當可以看到
    QueueConnecitonFactory(ptpQcf)和Queue(ptpQueue)對象,請見圖8-13。
    270
    圖8-13 顯示上下文
    8.5 JMS應用程序開發
    JMS 應用程序使用消息發送的點到點(PTP)或發布/預訂風格。沒有什么會阻止這兩
    種風格結合到單一的應用程序中;但是,JMS 集中在使用二者之一的應用程序上。JMS
    定義了這兩種風格,因為它們代表著當前使用的消息發送的兩種主要方法。由于許多消
    息發送系統僅支持二者之一,因此JMS 為每種風格都提供了不同的域,并為每個域定
    義了兼容。
    8.5.1 JMS點到點(PTP)模型
    點到點消息發送包括消息隊列處理。發送器發送消息到通常由單一接收器使用的特定隊
    列。在點到點通訊中,消息最多只有一個接收器。發送客戶機發送消息到包含目的(接
    收)客戶機消息的隊列。您可以將隊列看作信箱。許多客戶機可能發送消息到隊列,但
    消息僅由一個客戶機取出。而且,正如信箱一樣,消息直到刪除前會一直保存在隊列中。
    因此,接收客戶機的可用性不影響發送消息的能力。在點到點系統中,客戶機可以是發
    送器(消息生成器)、接收器(消息使用者)或二者都是。
    271
    8.5.2 點到點消息發送的編程方法
    圖8-14 顯示了在JMS 中開發點到點消息發送程序的高級步驟:
    圖8-14 JMS PTP 編程方法概述
    272
    點到點模型中的JMS 接口如下:
    .. QueueConnection
    .. QueueSession
    .. QueueSender
    .. QueueReceiver
    當使用JMS 時,連接不是直接生成的,而是利用連接庫構建的。這些庫對象可以儲存
    在JNDI 名稱空間中,從而隱藏了銷售商的特定實施。
    在點到點消息發送中,一般有兩種消息發送模式,如圖8-15 所示。第一種方法是發送
    -遺忘模型,第二種方法為請求/回復模式。
    圖8-15 點到點消息發送模型
    8.5.3 發送-遺忘
    利用發送-遺忘模式(或發射-忘記模式)時,不期待從(數據報)消息接收器獲取回
    復。
    簡單消息生成器應用程序
    我們的第一臺PTP 客戶機將創建一條文本消息,并將其發送到MQSeries 隊列。我們還
    將講解處理發送器發送的應用程序的接收器程序。有關步驟如下:
    273
    .. 在JNDI 名稱空間查找QueueConnectionFactory 和Queue;
    .. 獲取Queue Connection 對象;
    .. 創建QueueSession;
    .. 創建QueueSender;
    .. 創建TextMessage;
    .. 發送消息到Queue;
    .. 關閉以及斷開與連接對象的連接。
    程序PtpSender.java 顯示了有關開發點到點消息發送應用程序的有關步驟。程序發送一
    條簡單文本消息至MQSeries 隊列。
    例8-1 PtpSender.java
    Step 1 Import Necessary Packages(步驟一,導入所需的軟件包)
    import java.util.*;
    import javax.jms.*;
    import javax.naming.directory.*;
    import javax.naming.*;
    public class PtpSender {
    public static void main(String[] args) {
    String queueName = "ptpQueue";
    String qcfName = "ptpQcf" ;
    Context jndiContext = null;
    QueueConnectionFactory queueConnectionFactory = null;
    QueueConnection queueConnection = null;
    QueueSession queueSession = null;
    Queue queue = null;
    QueueSender queueSender = null;
    TextMessage message = null;
    String providerUrl = "iiop://itsog:900/ptpCtx" ;
    String initialContextFactory = "com.ibm.ejs.ns.jndi.CNInitialContextFactory";
    /**
    Step 2 set up an Initial Context for JNDI lookup(步驟二,建立初始上下文以便JNDI 查找)
    */
    try{
    Hashtable env = new Hashtable() ;
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory) ;
    env.put(Context.PROVIDER_URL , providerUrl );
    //env.put(Context.REFERRAL, "throw") ;
    jndiContext = new InitialDirContext(env);
    /**
    Step 3 get a QueueConnectionFactory. We will retrieve the
    QueueConnectionFacotry object named ptpQcf created in Persistent Name Server
    using JMSAdmin tool.(步驟三,獲取QueueConnectionFactory。我們將接收QueueConnectionFactory 對象
    指定的使用JMSAdmin 工具在Persistent Name Server 里創建的ptpQcf。)
    */
    queueConnectionFactory = (QueueConnectionFactory)jndiContext.lookup(qcfName);
    274
    /**
    Step 4 the Queue object from the JNDI namespace.(步驟四,來自JNDI 名稱空間的隊列對象)
    */
    queue = (Queue)jndiContext.lookup(queueName);
    /**
    Step 5 Create a QueueConnection from the QueueConnectionFactory(從隊列連接庫創建隊列連接)
    */
    queueConnection = queueConnectionFactory.createQueueConnection();
    /**
    Step 6 Start the QueueConnection.(步驟六,啟動隊列連接)
    */
    queueConnection.start();
    /**
    Step 7 Create a QueueSession object from the QueueConnection(步驟七,從隊列連接創建隊列會話)
    */
    queueSession = queueConnection.createQueueSession(false,
    Session.AUTO_ACKNOWLEDGE);
    /**
    Step 8 Create a QueueSender object for sending messages from the queue session.(步驟八,創建隊列發送器
    以便從隊列會話發送消息)
    */
    queueSender = queueSession.createSender(queue);
    /**
    Step 9 prepare a message object from the queuesession. we will create a
    textMessage message object.(步驟九,從隊列會話準備消息對象。我們將創建textMessage 消息對象。)
    */
    message = queueSession.createTextMessage();
    /**
    Step 10 Set the message you want, to the message object.(步驟十,設置您想要的消息到消息對象。)
    */
    message.setText("This is a Test Message from PtpSender Class " ) ;
    /**
    Step 11 Now we are ready to send the message.(步驟十一,現在我們已準備好發送消息。)
    */
    queueSender.send(message);
    System.out.println(“\n The Message has been sent”);
    /**
    Step 12 Close the Queue Connection Before exiting from the program.(步驟十二,在從程序退出前關閉隊列
    連接)
    */
    queueConnection.close();
    }catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    275
    簡單消息使用者應用程序
    我們的下一個客戶機應用程序是消息接收器應用程序,它獲取PtpSender 應用程序發送
    的消息并打印出控制臺上的消息。有關步驟如下:
    .. 在JNDI 名稱空間中查找QueueConnectionFactory 和Queue;
    .. 獲取Queue Connection 對象;
    .. 創建QueueSession;
    .. 創建QueueReceiver;
    .. 接收消息并顯示它;
    .. 關閉以及斷開與連接對象的連接。
    程序PtpReceiver.java 顯示了創建點到點消息使用者應用程序的有關步驟。應用程序從
    MQSeries 隊列獲取消息并顯示消息。
    例8-2 PtpReceiver.java
    //Step 1 Import the Necessary Packages(步驟一,導入所需的軟件包)
    import java.util.*;
    import javax.jms.*;
    import javax.naming.directory.*;
    import javax.naming.*;
    public class PtpReceiver {
    /**
    *The Main Method.
    * @param no args
    */
    public static void main(String[] args) {
    String queueName = "ptpQueue";
    String qcfName = "ptpQcf" ;
    Context jndiContext = null;
    QueueConnectionFactory queueConnectionFactory = null;
    QueueConnection queueConnection = null;
    QueueSession queueSession = null;
    Queue queue = null;
    QueueReceiver queueReceiver = null;
    TextMessage message = null;
    /* Provider url
    /For Persistent Name Server- iiop://iiopservername/contextname
    /For LDAP Server use ldap//cn=ContextName,o=OrganizationalSuffix,c=coutrysuffix
    eg. ldap://machineName/cn=ptpCtx,o=itso,c=uk
    */
    String providerUrl = "iiop://itsog/ptpCtx" ;
    String initialContextFactory = "com.ibm.ejs.ns.jndi.CNInitialContextFactory";
    276
    /**
    * Step 2 set up Initial Context for JNDI lookup(步驟二,建立初始上下文以便JNDI 查找)
    */
    try{
    Hashtable env = new Hashtable() ;
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory) ;
    env.put(Context.PROVIDER_URL , providerUrl );
    //env.put(Context.REFERRAL, "throw") ;
    jndiContext = new InitialDirContext(env);
    /**
    * Step 3 get the QueueConnectionFactory from the JNDI Namespace(步驟三,從JNDI 名稱空間獲取隊列連
    接庫)
    */
    queueConnectionFactory = (QueueConnectionFactory)jndiContext.lookup(qcfName);
    /**
    * Step 4 get the Queue Object from the JNDI Name space(步驟四,從JNDI 名稱空間獲取隊列對象)
    */
    queue = (Queue)jndiContext.lookup(queueName);
    /**
    * Step 5 Create a QueueConnection using the QueueConnectionFactory(步驟五,利用隊列連接庫創建隊列連
    接)
    */
    queueConnection = queueConnectionFactory.createQueueConnection();
    /*
    *Step 6 Connections are always created in stopped mode. You have to Explicitly
    start them. Start the queueConnection(步驟六,在停止模式里創建連接。您必須明確的啟動他們。啟動隊
    列連接。)
    */
    queueConnection.start();
    /**
    * Step 7 Create a queueSession object from the QueueConnection(步驟七,從隊列連接創建隊列會話對象)
    */
    queueSession = queueConnection.createQueueSession(false,
    Session.AUTO_ACKNOWLEDGE);
    /**
    * Step 8 Create a QueueReceiver from the queueSession(步驟八,從隊列會話創建隊列接收器)
    */
    queueReceiver = queueSession.createReceiver(queue);
    /**
    * Step 9 Receive Messages. Here we are implementing a synchronous message
    receiver. The receive call is in a loop so that it would process all the
    available messages in the queue(步驟九,接收消息。在此我們實施同步消息接收。循環進行接收調用從而
    能在隊列中處理所有可用消息。)
    */
    boolean eom = true;
    while (eom) {
    Message m = queueReceiver.receive(1);
    if (m != null) {
    if (m instanceof TextMessage) {
    message = (TextMessage) m;
    System.out.println("Reading message: " +
    message.getText()); }
    else {
    277
    break;
    }
    }
    else eom = false;
    }
    /**
    * Step 10 Close the connections(步驟十,關閉連接)
    */
    queueConnection.close();
    }
    catch(Exception e){
    e.printStackTrace();
    }
    }
    }
    8.5.4 請求/回復
    在請求/回復消息發送中,接收器接受請求消息后將發送回復到發送器。在接收器方,
    準備消息與PTP 中一樣,但除此之外JMSReplyToQueue 值將設置發送器期待從接收器
    回復的Queue Name。當獲取消息時,接收器可以使用回復到隊列名來發送回復消息至
    發送器。
    JMS 提供JMSReplyTo 消息標題字段,指定應當發送消息回復的目的地。JMSCorrelationId
    標題字段可以用在回復消息中,提供到請求消息的引用。
    請求/回復消息發送的應用程序設計考慮
    MQSeries 是種異步通訊機制。在請求/回復消息發送中,客戶機將消息放入隊列并等
    待回復時,在應用程序設計層次上必須小心。您不會愿意在隊列上無限制地等待回復消
    息的到達,因為您并不知道您的請求獲取回復要花多長時間。應用程序設計應當考慮到
    延遲回復和根本無回復的情況。您也可能希望在等待回復消息時考慮設置合適的超時
    值。
    如果在等待回復消息時使用超時的話,那么您可能希望在生成回復消息的遠程客戶機方
    考慮采用合適的過期時間值。在許多請求/回復情況下,您可以考慮為提高效能而使用
    非持久消息。使用非持久消息將會帶來顯著的效能改善。
    278
    非持久消息可以用三種方法發送。持久屬性可以用以下方法之一設置:
    .. 在創建MQSeries 隊列時直接在隊列管理器中的隊列對象上設置,或者您也可以在
    現有MQSeries Queue 上改變它。
    .. 在JNDI 中利用JMSAdmin 工具在隊列JMS 管理對象上設置。參數PERSISTENCE
    可用來指定您希望設置的持久值。不同的值如下:
    - APP:應用程序定義的持久值(這是默認的)
    - QDEF:MQSeries 隊列定義的持久值
    - PERS:持久的消息
    - NON:非持久的消息
    如果您希望以持久NON 定義隊列對象名,那么您可以使用JMSAdmin 來指定命令:
    DEFINE Q(ptpQueue) PERSISTENCE(NON)
    .. 在JMS 應用程序中對每條消息都使用DelieveryMode.NON.PERSISTENT 字段。消
    息持久性可以在QueueSender 上調整,或者也可以在發送方法調用上指定,但不能
    直接在消息上指定,請參見如下的例子:
    QueueSender sender = queueSession.createSender(queue) ;
    sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
    或者您也可以在發送消息時通過方法調用指定送達模式、優先級和使用期限等來設
    置送達模式。
    8.5.5 JMS發布/預訂模型
    與點到點通訊模型不同,發布/預訂模型可以讓一條消息送達多個接收器。發送客戶機
    指引或發布消息至多個客戶機可以預訂的主題。一個主題可以有多個發布器和多個預訂
    器。持久預訂或興趣在客戶機關閉和重啟時都存在。當客戶機關閉時,將儲存所有已送
    達主題的對象并在客戶機重新預訂時發送到客戶機。在發布/預訂系統中,客戶機可以
    是發布器(消息生成器)、預訂器(消息使用者)或二者都是。
    JMS 發布/預訂模型定義了在基于內容的層次中JMS 客戶機如何發布消息至已知的節
    點以及如何從已知的節點預訂消息。JMS 將這些節點稱作“主題”。
    279
    在本節中,我們使用的是發布和預訂這兩個術語,而不采用前面用到的生成和使用這兩
    個一般術語。我們可以把主題看作微型消息中介,它收集并分配指向它的消息。消息發
    送器依靠主題作為中間體從而獨立于預訂器,反過來也是如此。主題自動適應發布器和
    預訂器到來和離去。當代表發布器和預訂器的Java 對象存在時,發布器和預訂器是活動
    的。
    JMS 也支持預訂器可選的持久性,并在其不活動時“記住”其存在。MQSeries 發布/
    預訂使得應用程序不必知道有關目標應用程序的任何信息。它需要做的就是把它希望分
    享的信息發送到MQSeries 發布/預訂管理的標準目的地,并讓MQSeries 發布/預訂處
    理分配。同樣,目標應用程序不必了解其接收的信息來源的任何信息。
    圖8-16 顯示了用JMS 開發發布/預訂應用程序的有關步驟。
    280
    圖8-16 JMS 發布/預訂編程概述
    在JMS 實施發布/預訂消息發送模型中,所有特定銷售商實施都可以通過在java.jms
    中的以下接口引用。所有這些均包括在以下接口的實施中:
    .. QueueConnectionFactory
    .. TopicConnectionFactory
    .. Queue
    .. Topic
    在JMS 發布/預訂模型中,預訂主題時就可以實施主題異步預訂。
    281
    簡單JMS 發布/預訂應用程序
    在本節中,我們將用樣例程序JMSPublisher.java 來講解開發發布應用程序的有關步驟。
    編寫JMS 發布應用程序的有關步驟如下:
    1. 定義JMS 管理對象:
    a. 創建JNDI 上下文。
    我們使用以下命令來創建用于樣例程序中的名為psCtx 的JNDI 上下文:
    DEF CTX(psCtx)
    b. 利用以下命令改變到您剛剛創建的上下文中:
    CHG CTX(psCtx)
    c. 創建TopicConnectionFactory。
    以下命令將創建指向QueueManager ITSOG.QMGR1(它位于名為ITSOG 的主
    機上)的名為psTcf 的TopicConnectionFactory,它在默認端口1414 上進行監
    聽。用于客戶機連接的服務器連接為JMS.SRV.CHNL:
    DEF TCF(psTcf) TRANSPORT(CLIENT) QMANAGER(ITSOG.QMGR1) HOST(ITSOG)
    PORT(1414) CHANNEL(JMS.SRV.CHNL) BROKERQMGR(ITSOG.QMGR1)
    BROKERCONQ(SYSTEM.BROKER.CONTROL.QUEUE)
    BROKERPUBQ(SYSTEM.BROKER.DEFAULT.STREAM)
    BROKERSUBQ(SYSTEM.JMS.ND.SUBSCRIBER.QUEUE)
    BROKERCCSUBQ(SYSTEM.JMS.ND.CC.SUBSCRIBER.QUEUE)
    d. 定義JNDI 主題。
    以下命令為根主題JmsTest 下的名為SampleTopic 的主題創建名為psTopic 的
    Topic。
    DEF CTX(psCtx) TOPIC(JMSTest/SampleTopic)
    2. 在JNDI 名稱空間查找TopicConnectionFactory 和Topic;
    3. 創建Topic Connection;
    4. 創建TopicSession;
    5. 創建TopicPublisher;
    6. 創建TextMessage;
    7. 發布消息至Topic;
    8. 關閉以及斷開與連接對象的連接。
    282
    我們的第一個JMS 發布/預訂客戶機程序JMSPublisher.java 將創建一條文本消息并發
    送它到“SampleTopic”主題,它位于根主題JMSTest 之下。我們也將講解預訂主題
    “TestTopic”的預訂器程序。
    例8-3 JMSPublisher.java
    //Step 1 Import the necessary packages(步驟一,導入所需的軟件包。)
    import java.util.*;
    import javax.jms.*;
    import javax.naming.directory.*;
    import javax.naming.*;
    public class JMSPublisher {
    /**
    *The main method
    *@param no args
    */
    public static void main(String[] args) {
    String topicName = "cn=psTopic";
    String tcfName = "cn=psTcf" ;
    Contex jndiContext = null;
    TopicConnectionFactory topicConnectionFactory = null;
    TopicConnection topicConnection = null;
    TopicSession topicSession = null;
    Topic topic = null;
    TopicPublisher publisher = null;
    TextMessage message = null;
    String providerUrl = "ldap://itsog/cn=psCtx,o=itsog,c=uk" ;
    String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    //Step 2 Set up an Initial context for JNDI lookUp.(步驟二,建立初始上下文以便JNDI 查找。)
    try {
    Hashtable env = new Hashtable() ;
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory) ;
    env.put(Context.PROVIDER_URL , providerUrl );
    jndiContext = new InitialDirContext(env);
    //Step 3 Obtain a TopicConnection factory(步驟三,獲取主題連接庫。)
    topicConnectionFactory =
    (TopicConnectionFactory)jndiContext.lookup(tcfName);
    //Step 4 Create a Topic Connection using the connection factory object(步驟四,使用連接庫對象創建主題連
    接。)
    topicConnection = topicConnectionFactory.createTopicConnection();
    //Step 5 Start the topic connection.(步驟五,啟動主題連接。)
    topicConnection.start();
    //Step 6 Obtain a Topic from the JNDI(步驟六,從JNDI 獲取主題。)
    topic = (Topic)jndiContext.lookup(topicName);
    //Step 7 Create a Topic Session from the topic connection(步驟七,從主題連接創建主題會話。)
    283
    topicSession = topicConnection.createTopicSession(false,
    Session.AUTO_ACKNOWLEDGE);
    //Step 8 Create a topic publisher for the topic from the session.(步驟八,從會話為主題創建主題發布者。)
    publisher = topicSession.createPublisher(topic);
    //Step 9 Create a message object(步驟九,創建消息對象。)
    message = topicSession.createTextMessage();
    //Step 10 prepare the body of the message(步驟十,準備消息主體。)
    message.setText("This is a Test Message from JMSPublisher Class " ) ;
    //Step 11 Publish the message.(步驟十一,發布消息。)
    publisher.publish(message);
    //Step 12 Close the connections.(步驟十二,關閉連接。)
    publisher.close();
    topicSession.close();
    topicConnection.close();
    }
    catch(Exception e ) {
    e.printStackTrace();
    }
    }
    }
    簡單的JMS 預訂器應用程序
    在本節中,我們將通過創建一個樣例程序來講解開發JMS 預訂器應用程序的有關步驟。
    編寫JMS 預訂器應用程序的有關步驟如下:
    1. 在JNDI 名稱空間查找TopicConnectionFactory 和Topic;
    2. 創建Topic Connection;
    3. 創建TopicSession;
    4. 創建TopicSubscriber;
    5. 從Topic 接收預訂;
    6. 關閉并斷開與連接對象的連接。
    程序JMSSubscriber.java 是從“SampleTopic”主題(它位于根主題JMSTest 下)預訂消
    息的簡單預訂器應用程序。我們在例子中使用的是非可持續性預訂。
    例8-4 JMSSubscriber.java
    //Step 1 Import the necessary packages.(步驟一,導入所需軟件包。)
    import java.util.*;
    import javax.jms.*;
    import javax.naming.directory.*;
    import javax.naming.*;
    public class JMSSubscriber {
    /**
    * The main method
    284
    * @param no args
    */
    public static void main(String[] args) {
    String topicName = "cn=psTopic";
    String tcfName = "cn=psTcf" ;
    Context jndiContext = null;
    TopicConnectionFactory topicConnectionFactory = null;
    TopicConnection topicConnection = null;
    TopicSession topicSession = null;
    Topic topic = null;
    TopicSubscriber subscriber = null;
    TextMessage message = null;
    String providerUrl = "ldap://itsog/cn=psCtx,o=itsog,c=uk" ;
    String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    //Step 2 Set up Initial Context for JNDI lookup(步驟二,建立初始上下文以便JNDI 查找。)
    try{
    Hashtable env = new Hashtable() ;
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory) ;
    env.put(Context.PROVIDER_URL , providerUrl );
    env.put(Context.REFERRAL, "throw") ;
    jndiContext = new InitialDirContext(env);
    //Step 3 Get the TopicConnection factory from the JNDI Namespace(步驟三,從JNDI 名稱空間獲取主題
    連接庫。)
    topicConnectionFactory = (TopicConnectionFactory)jndiContext.lookup(tcfName);
    //Step 4 Create a TopicConnection(步驟四,創建主題連接。)
    topicConnection = topicConnectionFactory.createTopicConnection();
    //Step 5 Start The topic connection(步驟五,啟動主題連接。)
    topicConnection.start();
    //Step 6 Create a topic session from the topic connection(步驟六,從主題連接創建主題會話。)
    topicSession = topicConnection.createTopicSession(false,
    Session.AUTO_ACKNOWLEDGE);
    //Step 7 Obtain a Topic from the JNDI namespace(步驟七,從JNDI 名稱空間獲取主題。)
    topic = (Topic)jndiContext.lookup(topicName);
    //Step 8 Create a topic subscriber for the topic.(步驟八,為主題創建主題訂戶。)
    subscriber = topicSession.createSubscriber(topic);//Non durable subscriber(非持久預定者)
    //Step 9 Receive Subscription(步驟九,接收預訂。)
    message = (TextMessage)subscriber.receive();
    System.out.println("\n *** The Message is " + message.getText());
    //Step 10Close the connection and other open resources(步驟十,關閉連接和其它打開資源。)
    subscriber.close();
    topicSession.close();
    topicConnection.close();
    }
    catch(Exception e ) {
    e.printStackTrace();
    }
    }
    }
    285
    8.6 異步處理
    MQSeries JMS 提供了人們廣泛期待的MessageListener 接口。利用這個消息偵聽器功能,
    客戶機就可以注冊偵聽器對象到消息使用者。當消息到達使用者時,它通過調用
    onMessage 方法送達至客戶機。
    這是除利用其他方法(如觸發器、以等待發出接收或預訂調用或者在應用程序代碼中采
    用登記機制)外檢查新消息或預訂的另一種方法。當用偵聽器使用異步送達模式時,與
    消息使用者相關聯的整個會話都標志為異步的。相同的會話不能用來發出任何顯式接收
    調用。
    因為應用程序不發出顯式接收調用,因此在異步消息送達中,應用程序代碼可能不能獲
    取接受消息失敗所產生的例外。MQSeries JMS 提供了利用ExceptionListener 接口獲取異
    常的功能。當出現異常時,將調用onException 方法,而JMSException 將作為其參數傳
    遞到方法。
    8.6.1 消息偵聽器
    我們通過實施MessageListener 接口并在偵聽器的onMessage 方法中提供應用程序特定處
    理來創建消息偵聽器。我們將討論如何在消息使用者應用程序中實施簡單的消息偵聽
    器。
    我們首先創建偵聽器類(PTPListener.java),其擴展了JMSMessageListener 類并對
    onMessage 方法進行了實施。當消息到達時,消息作為自變量被送達至onMessage 方法。
    當消息到達時,我們就顯示消息。
    例8-5 PtpListener.java
    import java.io.*;
    import javax.jms.*;
    public class PtpListener implements MessageListener {
    /**
    * onMessage.
    */
    public void onMessage( Message message) {
    try {
    if (message instanceof TextMessage) {
    System.out.println( ((TextMessage)message).getText());
    286
    }
    } catch (JMSException e) {
    e.printStackTrace( );
    }
    }
    }
    在PtpAsyncConsumer.java 中,我們將講解消息使用者如何注冊偵聽器,從而使用消息
    異步處理。PtpAsyncConsumer.java 類將在PtpListener.java 中使用偵聽器來實施異步處理
    消息。您可以與我們在簡單發送器應用程序中介紹的PtpSender 應用程序一起來運行
    PtpAsyncConsumer。
    例8-6 PtpAsyncConsumer.java
    import java.util.*;
    import javax.jms.*;
    import javax.naming.directory.*;
    import javax.naming.*;
    public class PtpAsyncConsumer{
    String queueName = "cn=ptpQueue";
    String qcfName = "cn=ptpQcf" ;
    Context jndiContext = null;
    QueueConnectionFactory queueConnectionFactory = null;
    QueueConnection queueConnection = null;
    QueueSession queueSession = null;
    Queue queue = null;
    QueueReceiver queueReceiver = null;
    String providerUrl = "ldap://itsog/cn=ptpCtx,o=itsog,c=uk" ;
    String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    public static void main(java.lang.String[] args) {
    try {
    PtpAsyncConsumer asyncConsumer = new PtpAsyncConsumer() ;
    asyncConsumer.performTask();
    } catch (Exception e ){
    e.printStackTrace();
    }
    }
    /**
    * Method performTask Control the flow of control of the logical operations(方法performTask 可控制邏輯操
    作的控制流)
    287
    */
    public synchronized void performTask() throws Exception {
    System.out.println("\n Setting Up Initial JNDI Context ");
    Hashtable env = new Hashtable() ;
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory) ;
    env.put(Context.PROVIDER_URL , providerUrl );
    env.put(Context.REFERRAL, "throw") ;
    jndiContext = new InitialDirContext(env);
    System.out.println("\n Get QueueConnectionFactory ");
    queueConnectionFactory =
    (QueueConnectionFactory)jndiContext.lookup(qcfName);
    System.out.println("\n Get Queue ");
    queue = (Queue)jndiContext.lookup(queueName);
    System.out.println("\n Create Queue Connections ");
    queueConnection = queueConnectionFactory.createQueueConnection();
    System.out.println("\n Start Queue Connection ");
    queueConnection.start();
    System.out.println("\n Create Queue Session ");
    queueSession = queueConnection.createQueueSession(false,
    Session.AUTO_ACKNOWLEDGE);
    System.out.println("\n Create Queue Receiver ");
    queueReceiver = queueSession.createReceiver(queue);
    System.out.println("\n Register the Listener");
    PtpListener yahoo = new PtpListener();
    queueReceiver.setMessageListener(yahoo);
    //Wait for new messages.(等待新消息。)
    wait();
    }
    }
    8.6.2 異常偵聽器
    當以消息偵聽器利用異步消息送達模型時,應用程序代碼不能接到接收消息失敗產生的
    異常。這是因為應用程序代碼沒有顯式調用receive()或subscribe()方法。為了在異
    步處理中接到錯誤,您可以注冊ExceptionListener,它是實施onException()方法類的
    實例。異常偵聽器使得客戶機可以異步接收錯誤通知。如果注冊了異常偵聽器的話,那
    么當出現錯誤時,就會調用onMessage()方法,JMSException 對象則作為自變量被傳
    遞到該方法。異常偵聽器是在連接上設置的。
    288
    我們將用個非常簡單的應用程序來講解如何實施異常偵聽器。
    例8-7 JMSExceptionListener.java
    import java.io.*;
    import javax.jms.*;
    public class JMSExceptionListener implements ExceptionListener {
    /**
    * onException. We will just print the exception and exit from the program
    execution. Add suitable error handling and recovery logic depending on you
    use..(onException。我們將打印異常情況并且從程序的執行中退出。根據您的使用情況添加適當的錯誤
    處理和恢復邏輯。)
    */
    public void onException( JMSException e) {
    e.printStackTrace();
    System.exit(1);
    }
    }
    我們現在已經擁有了異常偵聽器,接下來就可以用JMSExceptionListener 實例、如下以
    setExceptionListener 方法注冊異常偵聽器到連接對象,從而在異步使用者中利用偵聽器:
    JMSExceptionListener exListener = new JMSExceptionListener( );
    queueConnection.setExceptionListener(exListener);
    setExceptionListner 方法為連接對象queueConnection 設置了異常偵聽器。
    289
    8.7 消息選擇器
    JMS 提供在隊列上查詢消息的功能,因此我們可以根據給定的標準選擇消息子集。我們
    可以把這看作是數據庫中的SQL 查詢功能。事實上,這種查找的語法就是以SQL92 條
    件表達的標準為基礎的。消息選擇器可以指向JMS 消息標題中的字段,也可以指向消
    息屬性中的字段,即應用程序定義的字段。
    計算消息選擇器的順序是在優先等級內從左至右。您可以利用插句來改變計算順序。選
    擇器字面值和操作器名是區分大小寫的。
    選擇器可能包括:
    .. 字面值:
    - 字符串字面值包括在單一引用中,一個被包括的單一引用由復式單一引用代
    表,如“literal”和“literal’s”。與Java String 字面值一樣,他們必須使用unicode
    字符編碼;
    - 精確數字字面值是沒有小數點的數字值,如57、-957、+62 等。支持Java 長
    型范圍內的數字。精確數字字面值使用Java 整數字面值語法;
    - 近似數字字面值是科學記數法表示的數字值(如7E3, -57.9E2)或帶有小數
    點的數字值(如7.、-95.7、+6.2 等)。支持Java 雙精度型范圍內的數字。近
    似字面值使用Java 浮點字面值語法;
    - Boolean 字面值真和假。
    .. 標識符
    - 標識符是必須以Java 標識符起始字符開始的無限長度字符序列,所有后續字符
    必須為Java 標識符部件字符。標識符起始字符是Character.isJavaIdentifierStart
    方法返回為真的任意字符。這包括‘_’ 和‘$’ 。標識符部件字符是
    Character.isJavaIdentifierPart 方法返回為真的任意字符。
    - 標識符不能是NULL, TRUE 或FALSE 名;
    - 標識符不能為NOT, AND, OR, BETWEEN, LIKE, IN 和IS;
    - 標識符可以是標題子段引用,也可以是屬性引用;
    - 標識符是區分大小寫的;
    - 消息標題子段引用限于JMSDelieveryMode, JMSPriority, JMSMessageID,
    JMSTimestamp, JMSCorrelationID 和JMSType 。JMSMessageID,
    290
    JMSCorrelationID 和JMSType 值可能為空,如果如此的話,那么它們將被作為
    NULL 值對待;
    - 任何以“JMSX”開始的名都是JMS 定義的屬性名;
    - 任何以“JMS_”開始的名都是供應方特定屬性名;
    - 任何不以“JMS”開始的名都是應用程序特定屬性名。如果引用消息中不存在
    的屬性,它的值則為NULL。如果它確實存在的話,那么它的值就是相應的屬
    性值。
    .. 空白空間與Java 中的定義一樣:空間、水平標簽、表單反饋和行終止符。
    .. 表達:
    - 選擇器是條件表達。計算為真的選擇器匹配。計算為假或未知的選擇器不匹配;
    - 算術表達由其自身、算術操作、帶數字值的標識符和數字字面值構成;
    - 條件表達由其自身、比較操作、邏輯操作、由boolean 值的標識符和boolean
    字面值構成;
    - 為表達計算排序的標準括號()被支持。
    .. 邏輯操作器的優先順序為:NOT, AND, OR
    .. 比較操作器:=, >, >=, <, <=, <> (不等于)
    - 只有相同類型的值才可以比較。這里有一個例外,就是我們可以比較精確數字
    值和近似數字值(要求的類型轉換由Java 數字升級定義)。如果嘗試比較不同
    類型的值的話,選擇器總為假;
    - 字符串和Boolean 比較限于=和<>。只有在兩個字符串包含相同的字符順序時,
    它們才是相等的;
    .. 算術操作器的優先順序如下:
    - +,- 一元的
    - *,/ 乘和除
    - +,- 加和減
    - 算術操作必須使用Java 數字提升。
    .. Arithmetic-expr1 [NOT] BETWEEN arithmetic-expr2 和arithmetic-expr3 比較操
    作器
    - 年齡介于15 到19 歲等于age >= 15 AND age <= 19;
    - 年齡不介于15 至19 之間等于age < 15 OR age > 19。
    291
    .. 標識符[NOT] IN (string-literal1, string-literal2,...)比較操作器,且標識符有一
    個字符串或NULL 值。
    - Country IN (’ UK’, ’US’, ’France’)對“UK”為真,對“Peru”為假。它等于
    如下表達:(Country = ’ UK’) OR (Country = ’ US’) OR(Country = ’
    France’);
    - Country NOT IN (’ UK’, ’US’, ’France’)對“UK”為假,對“Peru”為真。
    它等于如下表達:NOT ((Country = ’ UK’) OR (Country = ’US’) OR
    (Country = ’ France’));
    - 如果IN 或NOT IN 操作的標識符為NULL,那么操作的值為未知;
    - 標識符[NOT] LIKE pattern-value [ESCAPE escape-character]比較操作器,這
    里標識符有字符串值。Pattern-value 是個字符串字面值,其中‘_’代表任意單
    一字符。‘%’代表任意字符序列(包括空序列)。所有其他字符代表其本身。
    可選的透射字符是單一字符串字面值,其字符用于透射pattern-value 中‘_’和
    ‘%’的特別意義;
    - Phone LIKE ‘12%3’對“123”、“12993”為真,對“1234”為假;
    - Word LIKE ‘l_se’對“lose”為真,對“loose”為假;
    - Underscored LIKE ‘\_%’ ESCAPE ‘\’對“_foo”為真,對“bar”為假;
    - Phone NOT LIKE ‘12%3’對“123”和“12993”為假,對“1234”為真;
    - 如果LIKE 或NOT LIKE 操作標識符為NULL,那么操作的值為未知。
    .. 標識符IS NULL 比較操作器檢測空標題字段值或丟失屬性值。
    - prop_name IS NULL
    .. 標識符IS NOT NULL 比較操作器檢測非空標題字段值或屬性值的存在。
    - prop_name IS NOT NULL
    我們要求JMS 供應方在消息選擇器出現時校驗消息選擇器的語法正確性。提供語法不
    正確選擇器的方法必須以JMS InvalidSelectionException 為結果。
    以下消息選擇器選擇類型為汽車、顏色為藍、重量大于2500 磅的消息:
    “JMSType = ‘car’ AND color = ‘blue’ AND weight > 2500”
    292
    空值:標題字段和屬性值可能為NULL。計算選擇器表達的規則是,如果值為NULL,
    那么SQL 就把NULL 值作為未知。因此,任何含有NULL 值的算術操作比較,其結果
    都是未知值。
    8.7.1 用消息選擇器庫
    消息選擇器可以在消息上設置為用戶定義的屬性。在發送或發布方,我們可以通過利用
    名值對的設置屬性方法來設置屬性名和它的值。
    為了設置名為“testProperty”、值為100 以及數據類型為整數的屬性,我們可以在對象
    消息上如下設置屬性:
    messaget.setIntProperty(“testProperty”, 100) ;
    設置屬性方法用到兩個自變量。第一個自變量是類型字符串,也就是屬性值的名。第二
    個自變量是屬性值。我們應當根據希望設置值的數據類型選擇利用合適的設置屬性方法
    (setIntProperty 用于整數值,setStringProperty 用于字符串類型值等)。
    在消息使用者方,我們應當使用具有合適選擇標準的消息選擇器字符串。選擇標準是在
    創建消息使用者的時候指定的。
    我們使用的選擇標準是選擇屬性名為“testProperty”和值為100 的消息發送。我們可以
    用如下方法達到此目的:
    String selector = “testProperty = 100 “ ;
    queueReceiver = session.createReceiver(queueName, selector).
    用選擇器創建的消息使用者獲取屬性名為“testProperty”且值為100 的消息。
    一旦創建與消息使用者相關聯的選擇器,JMS 規范就不允許它改變。如果您需要不同標
    準的消息接收器的話,那么您可能需要創建另外的消息接收器。
    一旦用消息選擇器創建了消息接收器,您就可以利用消息使用者上的getMessageSelector
    ()方法來檢查選擇器值。
    在我們前面講解所用的queueReceiver 中,getMessageSelector 方法返回帶有選擇器值
    queReceiver.getMessageSelector()的字符串。這將返回testProperty=100。
    posted on 2008-02-17 22:40 李志峰 閱讀(4776) 評論(0)  編輯  收藏 所屬分類: JMS

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 可以免费观看一级毛片黄a| 成年人视频免费在线观看| 国产免费69成人精品视频| 亚洲日本va在线观看| 日韩版码免费福利视频| 亚洲人成在线中文字幕| 99久久精品日本一区二区免费| 亚洲码在线中文在线观看| 4455永久在线观免费看| 亚洲精品天堂在线观看| 午夜男人一级毛片免费| 亚洲av日韩av永久在线观看| 四虎免费永久在线播放| 国产精品亚洲专区一区| 亚洲高清成人一区二区三区| 二级毛片免费观看全程| 亚洲成色在线综合网站| 8888四色奇米在线观看免费看| 亚洲毛片基地日韩毛片基地| 女人18毛片水真多免费播放| 久久精品亚洲日本波多野结衣| 亚洲第一区精品观看| 韩国免费A级毛片久久| 亚洲午夜精品久久久久久人妖| 亚洲一级免费视频| 亚洲另类无码一区二区三区| 免费在线黄色网址| 麻豆精品不卡国产免费看| 亚洲精品在线播放| 国产成人3p视频免费观看 | 国产一卡2卡3卡4卡2021免费观看 国产一卡2卡3卡4卡无卡免费视频 | 一个人看的www免费在线视频| 国产亚洲免费的视频看| 综合在线免费视频| 四虎影视永久在线精品免费| 亚洲欧洲日产国码久在线观看| 成人免费无码大片A毛片抽搐色欲| jizz免费观看| 亚洲伊人久久大香线蕉影院| 免费少妇a级毛片人成网| 99久9在线|免费|