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

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

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

    細(xì)心!用心!耐心!

    吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學(xué)業(yè),五六點(diǎn)粗墨,七八筆買賣,九十道人情。

    BlogJava 聯(lián)系 聚合 管理
      1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks

    使用 JMS 技術(shù)作為數(shù)據(jù)復(fù)制的解決方案

     

    本文概述了如何使用 Java 消息傳遞系統(tǒng)(JMS)進(jìn)行大型文件的復(fù)制。Dan Drasin 描
    述了解決 Applied Reasoning 公司客戶的分布式數(shù)據(jù)問題的方案,并提供了基于 JMS
    的解決方案的實(shí)現(xiàn)細(xì)節(jié)。他討論了其中的優(yōu)點(diǎn)、一些潛在缺陷以及將 IBM MQSeries(現(xiàn)
    在稱為 WebSphere MQ)成功設(shè)置為 JMS 服務(wù)器的一些實(shí)際指示信息。
    背景
    在思考消息傳遞解決方案時(shí),您可能會(huì)想到一個(gè)通過遠(yuǎn)程消息調(diào)用機(jī)制來集成兩個(gè)不同
    應(yīng)用程序的系統(tǒng)。一般來講,對于不常通信的分布式實(shí)體以及數(shù)據(jù)傳輸量不是很多這樣
    的情況,常常使用這種耦合。較經(jīng)典的示例是,連接到異構(gòu)后端和入口的同構(gòu)接口,這
    些后端和入口指派進(jìn)行用戶請求的后端處理,然后為最終用戶表示而對那些請求進(jìn)行重
    新格式化。
    消息傳遞方法中的公共線程一直有這樣的假定:雖然消息傳遞解決方案在系統(tǒng)之間提供
    健壯、高度可用的通信,但它基本上效率很低,只用來作為在無法避免與外部系統(tǒng)通信
    時(shí)的最后一種手段。在出現(xiàn)遠(yuǎn)程方法調(diào)用(RMC)時(shí)關(guān)于消息傳遞的這種觀點(diǎn)就開始流行
    一直到出現(xiàn)了更現(xiàn)代的象 CORBA 和 DCOM 那樣的消息傳遞解決方案,而且,通常所應(yīng)用
    的消息傳遞只局限于解決幾類問題。
    目標(biāo)
    在過去的十年中,人們對分布式系統(tǒng)需求有了更深入的理解。新興技術(shù)(象 Java 和 .
    NET)已經(jīng)包含了代碼分布來作為它們基本編程模型的一部分。通過這樣做,這些技術(shù)已
    將高度可用性和容錯(cuò)性融入到消息傳遞中,同時(shí)鼓勵(lì)那些提供解決方案的供應(yīng)商交付一
    些系統(tǒng),這些系統(tǒng)在更廣范圍的問題上考慮性能。
    近來我們公司被要求實(shí)現(xiàn)文件分布和復(fù)制的解決方案,在以前這樣的方案需要集成安全
    的 FTP、數(shù)據(jù)庫復(fù)制和其它一次性解決方案的定制系統(tǒng)。我們沒有一味地埋頭按照定制
    開發(fā)的道路前進(jìn),而是研究了將最新的消息傳遞解決方案應(yīng)用到這個(gè)問題的可能性。我
    們發(fā)現(xiàn) JMS 不僅為信息傳送提供必要的基礎(chǔ)結(jié)構(gòu),而且它還能處理我們客戶要求的、與
    服務(wù)質(zhì)量、安全性、可靠性和性能有關(guān)的所有基礎(chǔ)結(jié)構(gòu)問題。本文描述了我們團(tuán)隊(duì)面臨
    的挑戰(zhàn),以及 JMS(以 MQSeries 的形式)如何讓我們滿足并超越客戶的要求。
    問題
    我們的客戶面臨一個(gè)重大的分布式數(shù)據(jù)難題,在全國范圍內(nèi)有許多呼叫中心,在全國各
    地的呼叫中心里接線員要記錄與客戶之間的交互。必須快速可靠地在遠(yuǎn)程數(shù)據(jù)中心為這
    些記錄建立索引并存檔。建立索引和存檔的存儲(chǔ)過程不能影響接線員的系統(tǒng)記錄和存儲(chǔ)
    接線員正在與客戶交互的信息的能力。該客戶已經(jīng)有了一個(gè)包含組合起來的代碼、VPN
    和其它技術(shù)的系統(tǒng)。但是,現(xiàn)有的解決方案遠(yuǎn)遠(yuǎn)達(dá)不到性能和可靠性上的目標(biāo),并且它
    是一種拙劣的技術(shù),難以理解并且維護(hù)費(fèi)用很高。
    在開發(fā)替代客戶原有系統(tǒng)時(shí),我們考慮了 JMS 和多種非 JMS 的解決方案,尤其是那些
    基于 FTP 和安全復(fù)制(SCP)的解決方案。然而,非 JMS 解決方案有兩個(gè)主要缺點(diǎn):
    它們對于安全性方面的缺陷一籌莫展。(FTP 上的安全性漏洞已經(jīng)人人皆知,并且人們
    對此已廣泛地作了記載。如果需要這方面的例子,請參閱參考資料。)
    它們提供的基礎(chǔ)結(jié)構(gòu)只適用于實(shí)際的數(shù)據(jù)傳送,而對于處理可靠性、容錯(cuò)性、安全性、
    平臺(tái)獨(dú)立性以及性能優(yōu)化等問題,需要定制開發(fā)來解決。
    我們團(tuán)隊(duì)最后得出結(jié)論,對于添加這些額外的特性所需的開發(fā)工作是讓人望而卻步的,
    因此我們決定選用 JMS 解決方案,它可以擺脫這些問題。
    解決方案
    我們開發(fā)了一個(gè)基于 JMS 的系統(tǒng),它:
    為已記錄的多媒體文件提供可靠存檔
    支持可擴(kuò)展性,可以使多個(gè)數(shù)據(jù)中心接收文件
    支持對其它數(shù)據(jù)類型進(jìn)行存檔
    我們這里正討論的文件比以前那些涉及消息傳遞解決方案的項(xiàng)目中傳送的數(shù)據(jù)還要大(
    50K - 500K)。我們第一個(gè)任務(wù)是確保數(shù)據(jù)大小不會(huì)影響 JMS 解決方案。通過測試系統(tǒng)
    傳遞各種大小的消息有效負(fù)載時(shí)的性能,我們評估了包括 IBM MQSeries 在內(nèi)的許多 J
    MS 解決方案。結(jié)果顯示:經(jīng)過適當(dāng)配置,大小達(dá)到 1 兆的消息不會(huì)對整個(gè)系統(tǒng)性能產(chǎn)
    生顯著影響。因?yàn)槌WR認(rèn)為消息傳遞解決方案只適用于定期的、小的有效負(fù)載,所以我
    們的結(jié)果是一個(gè)重大發(fā)現(xiàn)。我們繼續(xù)分析系統(tǒng)的體系結(jié)構(gòu)(圖 1 中概述了此體系結(jié)構(gòu))
    ,它可以提供客戶需要的安全性、高可用性和可靠性。
    圖 1. 高級系統(tǒng)體系結(jié)構(gòu)
    現(xiàn)有的基礎(chǔ)結(jié)構(gòu)在每個(gè)客戶機(jī)上有一個(gè)系統(tǒng),當(dāng)接線員與用戶之間進(jìn)行交互時(shí),它創(chuàng)建
    多媒體文件,以此作為響應(yīng)。此外,還需對這些文件進(jìn)行存檔。我們的系統(tǒng)啟動(dòng)一個(gè)進(jìn)
    程(運(yùn)行在每個(gè)機(jī)器上)并在已知目錄中查找這些文件。當(dāng)檢測到新文件時(shí),進(jìn)程將它
    們打包成 JMS 有效負(fù)載并發(fā)送到其中一個(gè)數(shù)據(jù)中心的 JMS 服務(wù)器以便傳遞。一旦 JMS
    服務(wù)器確認(rèn)收到,則除去發(fā)送方中的這些文件。JMS 服務(wù)器將該數(shù)據(jù)傳送到數(shù)據(jù)中心內(nèi)
    的一個(gè)可用處理程序上,進(jìn)行存檔。
    主要概念
    JMS 是特定于 Java 的消息傳遞和排隊(duì)的實(shí)現(xiàn)。在消息傳遞和排隊(duì)中有兩個(gè)基本思想:

    系統(tǒng)通過使用不連續(xù)的數(shù)據(jù)包進(jìn)行通信,這些數(shù)據(jù)包都有一個(gè)有效負(fù)載(即要傳送的信
    息)和屬性(即該信息的特征以及它應(yīng)如何通信)。這個(gè)數(shù)據(jù)包稱為 消息。
    消息不是被發(fā)送給系統(tǒng),而是被發(fā)送到一個(gè)獨(dú)立的保存區(qū)域。可以根據(jù)您的需要確定保
    存區(qū)域的數(shù)量,通過唯一的名稱,可以標(biāo)識并定位它們。每個(gè)保存區(qū)域都可以接收消息
    ,并且根據(jù)配置的不同,該區(qū)域?qū)⒚總€(gè)消息要么傳遞給所有感興趣的系統(tǒng)(發(fā)布-訂閱)
    ,要么傳遞給第一個(gè)感興趣的系統(tǒng)(點(diǎn)對點(diǎn))。這個(gè)保存區(qū)域稱為 目的地。
    我們構(gòu)建的系統(tǒng)采用點(diǎn)對點(diǎn)的目的地,在 JMS 中稱為隊(duì)列。排隊(duì)是圖 1 中顯示的系統(tǒng)
    設(shè)計(jì)的一個(gè)重要方面。該圖顯示了消息正從 JMS 代理直接傳送到接收方的客戶機(jī)上,但
    這并不十分準(zhǔn)確。實(shí)際上,消息被傳送到一個(gè)隊(duì)列中,接收方客戶機(jī)從隊(duì)列中檢索它們
    。稍后我們研究實(shí)現(xiàn)細(xì)節(jié)時(shí),這個(gè)區(qū)別將變得非常重要,因?yàn)樗屜到y(tǒng)并行地處理收到
    的消息。
    跨平臺(tái)和交叉供應(yīng)商
    對我們客戶機(jī)來說盡量減少對某家供應(yīng)商的依賴,這意味著,我們所設(shè)計(jì)的代碼應(yīng)該使
    由于更改了 JMS 供應(yīng)商而帶來的影響降至最低,這是十分重要的。JMS 的一個(gè)主要優(yōu)點(diǎn)
    是它以廣泛的業(yè)界支持和開放標(biāo)準(zhǔn)為基礎(chǔ),因此有了正確設(shè)計(jì)的代碼,我們就可以讓系
    統(tǒng)使用任何 JMS 系統(tǒng)。(可以對現(xiàn)有系統(tǒng)進(jìn)行直接改進(jìn),專門設(shè)計(jì)來使系統(tǒng)在某套硬件
    上運(yùn)行并能與特定于供應(yīng)商的解決方案相匹配。)
    通過將所有特定于供應(yīng)商的調(diào)用封裝在稱為 JMSProvider 的類中,就可以輕松實(shí)現(xiàn)平臺(tái)
    獨(dú)立性。這些 Provider 類處理特定于供應(yīng)商的問題,例如工廠查詢、錯(cuò)誤處理、連接
    創(chuàng)建和消息特性設(shè)置等。請參閱下面清單 1 中的示例代碼。
    清單 1. 在類 ar.jms.JmsProvider 中
    public QueueConnection createConnection() throws JMSException {
    return getConnectionFactory().createQueueConnection(getUserName(),
    getPassword());
    }
    通過利用“Java 命名和目錄接口(JNDI)”,我們將特定于供應(yīng)商的設(shè)置存儲(chǔ)在一個(gè)資
    源庫(例如,LDAP 庫)中,這樣實(shí)際代碼就幾乎不需要特定于供應(yīng)商的引用。只需要少
    量特定于供應(yīng)商的代碼來處理一些特性,但是可以將這樣的代碼限定于一些“適配器”
    類,并將它保存在應(yīng)用程序代碼之外。請參閱下面清單 2 中的示例代碼。因?yàn)?JMS 被
    設(shè)計(jì)用來方便地使用 JNDI,所以與其它解決方案相比,這是另一個(gè)直接優(yōu)點(diǎn) ― 配置信
    息的集中存儲(chǔ)不僅可以保存基于文本的信息,而且還可以存儲(chǔ)已配置的對象。
    清單 2. 在類 ar.jms.JmsProvider 中
    public final static String
    CONNECTION_FACTORY_LOOKUP_NAME_KEY = "CONNECTION_FACTORY_LOOKUP_NAME";
    public final static
    String FILE_TRANSFER_QUEUE_LOOKUP_NAME_KEY =
    "FILE_TRANSFER_QUEUE_LOOKUP_NAME";
    public final static String
    JMS_PROVIDER_CLASS_KEY = "JMS_PROVIDER_CLASS";
    public void init() throws NamingException {
    InitialContext jndi = createInitialContext();
    initConnectionFactory(jndi);
    initFileTransferQueue(jndi);
    }
    public QueueConnection createConnection() throws JMSException {return
    getConnectionFactory().createQueueConnection(getUserName(),
    getPassword());
    }
    public void initConnectionFactory(InitialContext jndi) throws
    NamingException {
    setConnectionFactory((QueueConnectionFactory)jndi.lookup
    (getProperties().getProperty(CONNECTION_FACTORY_LOOKUP_NAME
    _KEY)));
    }
    public void initFileTransferQueue(InitialContext jndi) throws
    NamingException {
    setFileTransferQueue((Queue) jndi.lookup
    (getProperties().getProperty(FILE_TRANSFER_QUEUE_LOOKUP_NAM
    E_KEY)));
    }
    跳出傳統(tǒng)模式,JMS 解決方案允許以可靠的方式傳送消息,即一旦確認(rèn)已將消息傳送到
    JMS 服務(wù)器,就將它傳送至尋址到的目的地(隊(duì)列)。MQSeries 也不例外。一旦成功
    執(zhí)行了將消息發(fā)送到服務(wù)器的代碼,客戶機(jī)就保證目的地最終會(huì)接收到消息,即使所討
    論的服務(wù)器在處理過程中出現(xiàn)故障(如果目的地暫時(shí)不可用,或者 JMS 服務(wù)器死機(jī)等等
    )。請參閱下面清單 3 中的示例代碼。下面代碼中的類實(shí)際上負(fù)責(zé)一旦它確定需要發(fā)送
    文件,就執(zhí)行數(shù)據(jù)的發(fā)送。
    通過將消息配置為持久消息,我們可以保證一旦目的地(隊(duì)列)接收到消息,那么消息
    將保留在那里直到它在該隊(duì)列中被檢索為止 ― 即使在系統(tǒng)有故障期間。因此,一旦安
    全地將消息傳送到本地 JMS 服務(wù)器,就可以刪除它了。不能過高估計(jì)克服系統(tǒng)故障的能
    力;對周期性系統(tǒng)故障的處理是開發(fā)分布式存檔解決方案最重要的問題之一。客戶現(xiàn)有
    系統(tǒng)上處理故障情況的代碼很復(fù)雜很脆弱,而且對這些故障的處理和維護(hù)費(fèi)用很高。通
    過一個(gè)健壯的、經(jīng)測試成功的商業(yè)解決方案,JMS 使我們能解決所有這些問題。
    清單 3. 來自類 ar.jms.file.send.ConnectionElement
    public void sendMessage(byte[] payload, boolean persistent) throws
    SendFailedException {
    QueueSender sender = null;
    try {
    Message message = createMessage(payload);
    sender = createSender
    (persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

    sender.send(message);
    getClient().getLogService().logInfo(getName() +
    " sent message " + message.getJMSMessageID() + ".");
    } catch (JMSException exception) {
    getClient().getLogService().logError
    ("JMS exception processing " + getName(),exception);
    stop();
    throw new SendFailedException("JMS Message Send Failed");
    }
    try {
    sender.close();
    } catch (JMSException ignore) {
    getClient().getLogService().logInfo(getName() + " failed to
    close sender. Processing will continue.");
    }
    }
    這個(gè)解決方案的關(guān)鍵是配置 JMS 消息和服務(wù)器來同時(shí)提供令人滿意的性能和服務(wù)質(zhì)量。
    JMS 規(guī)范定義了配置選項(xiàng),并通過所有商業(yè)解決方案實(shí)現(xiàn)它們。但是,配置的確切方法
    根據(jù)不同的供應(yīng)商而有所不同。
    設(shè)置
    我們創(chuàng)建的體系結(jié)構(gòu)和系統(tǒng)具有通用性且很強(qiáng)大。但是,對于一些移動(dòng)部件,必須使用
    正確的方式配置并鉤連它們。以下內(nèi)容是有關(guān)將 MQSeries 成功地設(shè)置為 JMS 服務(wù)器的
    概述、一些潛在缺陷和實(shí)際的指示信息。
    對于 MQSeries,首先設(shè)置 JNDI 服務(wù)器來檢索特定于實(shí)現(xiàn)的設(shè)置,在這種情況下是 JM
    S 連接工廠(JMS Connection Factory)。有許多不同方法來實(shí)現(xiàn)這個(gè)操作,但適宜的
    通用選項(xiàng)是輕量級目錄訪問協(xié)議(LDAP)服務(wù)器。我們選擇使用 Qualcomm SLAPD。一旦
    安裝好并運(yùn)行該服務(wù)器,就可以用 MQSeries 管理工具(JMSAdmin.bat)來設(shè)置該服務(wù)
    器并將其作為 MQ 對象信息庫來使用。請參閱參考資料,獲取有關(guān)講述該過程的實(shí)用書
    籍的鏈接。同時(shí),在設(shè)置期間,要特別注意在 IBM MQSeries 之上設(shè)置 JMS 的 IBM 文
    檔,這很重要。這個(gè)過程涉及創(chuàng)建一些隊(duì)列和其它對象,這些隊(duì)列和對象是特定于 JMS
    使用并且不屬于標(biāo)準(zhǔn) MQSeries 安裝的。
    完成 JNDI/LDAP 和 JMS 服務(wù)器的設(shè)置后,就可以準(zhǔn)備配置客戶機(jī)了。第一步是理解 J
    MS 如何與 IBM 的標(biāo)準(zhǔn) MQSeries 實(shí)現(xiàn)交互。MQSeries 的 Java 客戶機(jī)能以兩種模式之
    一進(jìn)行交互:客戶機(jī)和綁定模式。只能通過 Java Applet 來使用客戶機(jī)模式,而綁定模
    式取決于客戶機(jī)上的 DLL 或者對象庫。因?yàn)閷?shí)現(xiàn)的特性,當(dāng)使用用于 JMS 連接信息的
    LDAP 服務(wù)器時(shí),只能使用綁定模式。(不清楚為什么有這個(gè)限制,但它確實(shí)存在。)
    因此,將用戶登錄和密碼存儲(chǔ)在一個(gè)全局位置(com.ibm.mq.MQEnvironment.class)而
    不是在連接時(shí)傳遞它們。要解決這些供應(yīng)商問題,我們創(chuàng)建了標(biāo)準(zhǔn) JmsProvider 類(稱
    為 MQSeriesProvider)的子類。這個(gè)類將完成的唯一操作是覆蓋如何創(chuàng)建連接。不象清
    單 1 中那樣
    newQueueConnection = getConnectionFactory().createQueueConnection(getUserNam
    e(),getPassword));
    進(jìn)行調(diào)用,我們必須調(diào)用
    newQueueConnection = getConnectionFactory().createQueueConnection();
    最后,您需要將特定于 JMS 的元素(如隊(duì)列、隊(duì)列管理器、隊(duì)列工廠等等)提供給客戶
    機(jī)。現(xiàn)在,使用 LDAP 和 JNDI 的原因就變得很明顯:我們使用 LDAP 服務(wù)器來存儲(chǔ)這
    些元素并使用外部文件保存那些 LDAP 對象的鍵。LDAP 服務(wù)器可以作為 JNDI 服務(wù)器并
    通過返回存儲(chǔ)的對象來響應(yīng)名稱查詢。這就是清單 2 中代碼的工作原理。JMS 元素的名
    稱可從類的靜態(tài)變量(對于缺省名稱)或者外部文件(使用非缺省的其它名稱)中獲取
    。簡而言之,向 LDAP 服務(wù)器請求鍵(我們正討論的)中存儲(chǔ)的對象,并返回我們感興
    趣的 JMS 對象(在這種情況下)。
    我們基于 JMS 的解決方案通過使用現(xiàn)有的組件更方便地實(shí)現(xiàn)統(tǒng)一的、跨平臺(tái)和交叉供應(yīng)
    商的配置環(huán)境。現(xiàn)在我們的代碼已盡可能地成為獨(dú)立于特定于平臺(tái)和特定于供應(yīng)商的設(shè)
    置。
    應(yīng)用程序
    應(yīng)用程序中有兩個(gè)關(guān)鍵組件:發(fā)送器和接收器。發(fā)送器啟動(dòng)一個(gè)后臺(tái)程序,它在目錄中
    輪詢需要存檔的文件,而接收器只是等待將要傳遞的 JMS 消息,然后將該消息中包含的
    文件存檔。JMS API 使我們幾乎無需關(guān)注正使用的特定 JMS 實(shí)現(xiàn)就可以定義這些組件。

    發(fā)送器由三個(gè)主要部件組成:
    JMSProvider,用于創(chuàng)建連接
    ConnectionPool,用于獲取現(xiàn)有的空閑連接(我們稱之為 JMSConnection)
    輪詢程序,監(jiān)視需要傳送的文件。
    在啟動(dòng)時(shí),使用 JMSProvider 來創(chuàng)建一些到 JMS 服務(wù)器的準(zhǔn)備就緒的連接。這些連接
    放置在池中,然后啟動(dòng)輪詢程序。當(dāng)輪詢程序檢測到需要傳送文件時(shí),它就創(chuàng)建一個(gè)獨(dú)
    立線程來處理這個(gè)文件。(可以通過派生(forking),創(chuàng)建一個(gè)獨(dú)立的線程來創(chuàng)建消息
    和進(jìn)行傳送操作,描述該過程非常簡單。但在實(shí)際應(yīng)用中,常常將合用(pooling)與循
    環(huán)組合起來使用,這樣可以確保很少創(chuàng)建新線程,而是重用線程。但是,那個(gè)過程相當(dāng)
    復(fù)雜,過多的說明會(huì)分散本文的中心主題 ― JMS。)
    在獨(dú)立線程中,輪詢程序接著從連接池中獲取 JMSConnection,用它來創(chuàng)建一個(gè) Bytes
    Message,并將這個(gè)文件的二進(jìn)制內(nèi)容放入那個(gè)消息中。最后這個(gè)消息查找到接收器,并
    發(fā)送到 JMS 服務(wù)器,接著將 JMSConnection 返回給 ConnectionPool。這個(gè)發(fā)送過程的
    部分步驟顯示在下面的圖 2 中。
    圖 2. 發(fā)送器過程
    接收器是一個(gè)較簡單的組件;它啟動(dòng)一些 FileListener 來等待將要放置在接收器隊(duì)列
    中的消息。下面的清單 4 中的代碼顯示了 FileListener 設(shè)置處理過程。圖 6 中的類
    實(shí)際上負(fù)責(zé)從隊(duì)列中檢索消息并對它們進(jìn)行存檔。JMS 保證隊(duì)列發(fā)送每個(gè)消息的次數(shù)僅
    一次,所以我們可以安全啟動(dòng)許多不同的 FileListener 線程并且知道每個(gè)消息(因此
    每個(gè)文件)只處理一次。這個(gè)保證是使用基于 JMS 解決方案的另一個(gè)重要優(yōu)點(diǎn)。在自己
    設(shè)計(jì)的解決方案中開發(fā)這樣的功能(比如基于 FTP 的功能),花銷很大且易出錯(cuò)。
    清單 4:來自類 ar.jms.file.receive.FileListener public void startOn(Queue qu
    eue) {
    setQueue(queue);
    createConnection();
    try {
    createSession();
    createReceiver();
    getConnection().start(); // this starts
    the queue listener
    } catch (JMSException exception) {
    // Handle the exception
    }
    }
    public void createReceiver() throws javax.jms.JMSException {
    try {
    QueueReceiver receiver = getSession().
    createReceiver(getQueue());
    receiver.setMessageListener(this);
    } catch (JMSException exception) {
    // Handle the exception
    }
    }
    public void createSession() throws JMSException {
    setSession(getConnection().
    createQueueSession(false, Session.AUTO_ACKNOWLEDGE));
    }
    public void createConnection() {
    while (!hasConnection()) {
    try {
    setConnection(getClient().createConnection());
    } catch (JMSException exception) {
    // Connections drop periodically on the
    internet, log and try again.
    try {
    Thread.sleep(2000);
    } catch
    (java.lang.InterruptedException ignored) {
    }
    }
    }
    }
    以回調(diào)的方式編寫消息處理代碼,回調(diào)是當(dāng)將消息傳遞給 FileListener 時(shí),JMS 自動(dòng)
    調(diào)用的方法。這個(gè)消息的代碼顯示在下面的清單 5 中。
    清單 5. 來自類 ar.jms.file.receive.FileListener public void onMessage(Messag
    e message) {
    BytesMessage byteMessage = ((BytesMessage) message);
    OutputStream stream =
    new BufferedOutputStream(
    new FileOutputStream(getFilenameFor(message)));
    byte[] buffer = new byte[getFileBufferSize()];
    int length = 0;
    try {
    while ((length = byteMessage.readBytes(buffer)) != -1) {
    stream.write(buffer, 0, length);
    }
    stream.close();
    } catch (JMSException exception) {
    // Handle the JMSException
    } catch (IOException exception) {
    // Handle the IOException
    }
    }
    在設(shè)置接收器時(shí)要記住一條訣竅:在所有 FileListener 啟動(dòng)后,確保啟動(dòng)這些 FileL
    istener 的原始線程繼續(xù)運(yùn)行。這是必要的,因?yàn)槟承?JMS 實(shí)現(xiàn)在守護(hù)程序的線程中啟
    動(dòng) QueueListener。所以,如果正在運(yùn)行的唯一線程是守護(hù)程序的線程,那么 Java 虛
    擬機(jī)(JVM)可能會(huì)過早地意外退出。下面的清單 6 顯示了一些防止這種情況發(fā)生的簡
    單代碼。
    清單 6. 至少使一個(gè)非守護(hù)程序的線程保持運(yùn)行 public static void main(String[]
    args) {
    ReceiverClient newReceiverClient = new ReceiverClient();
    newReceiverClient.init();
    setSoleInstance(newReceiverClient);
    while(!finished) { // This prevents the VM from exiting early
    try {
    Thread.sleep(1000);
    } catch (InterruptedException ex) {
    }
    }
    }
    結(jié)束語
    在該項(xiàng)目的最初實(shí)現(xiàn)之后,我們添加了一些功能,象消息壓縮、當(dāng)位置無法到達(dá)時(shí)的自
    動(dòng)恢復(fù)、聯(lián)合消息代理、安全性、健壯的日志記錄、管理等等。添加這些功能很容易,
    因?yàn)?JMS 提供了開放模型,而且我們的體系結(jié)構(gòu)也很健壯。構(gòu)建整個(gè)系統(tǒng)花了六個(gè)星期
    的時(shí)間,并且還很快地替換了客戶一直使用的現(xiàn)有的、勞動(dòng)密集型的系統(tǒng)。在這些天里
    ,系統(tǒng)已經(jīng)超出了所有的基準(zhǔn)測試程序的標(biāo)準(zhǔn)并且已更正了原來系統(tǒng)遺留下來的錯(cuò)誤。
    這個(gè)項(xiàng)目不單超出了客戶的期望,還證明了 JMS 是一個(gè)可行的解決方案,不僅適用于小
    型、面向消息的應(yīng)用程序,而且還適用于大規(guī)模的、重要任務(wù)的數(shù)據(jù)傳送操作。
    參考資料
    獲取更多信息或者下載 Qualcomm slapd。
    訪問 JMS 主頁。
    回顧 FTP 的安全性問題。
    查閱 Giotta 等人編寫的 JMS 設(shè)置一書:“Professional JMS Programming”。
    學(xué)習(xí)有關(guān) IBM MQSeries 的更多內(nèi)容或者下載測試版本。
    閱讀 developerWorks 上的相關(guān)文章:“Java theory and practice: Should you use
    JMS in your next entERPrise application?”。
    閱讀 developerWorks 上 Daniel 以前的文章:“The profound impact of hardware,
    software, and networking decisions”。

    posted on 2007-05-06 12:55 張金鵬 閱讀(189) 評論(0)  編輯  收藏

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 青青青国产在线观看免费| 免费在线观看黄网站| 中文字幕乱码亚洲无线三区 | 91久久成人免费| 亚洲另类无码专区首页| 亚洲伊人成无码综合网| 又大又硬又爽又粗又快的视频免费| 亚洲熟妇无码AV| 亚洲精品成人片在线观看精品字幕| 四虎1515hh永久久免费| 一区二区在线免费视频| 亚洲视频国产视频| 免费一级毛片不卡在线播放| 91大神免费观看| 一级毛片免费视频网站| 亚洲日日做天天做日日谢| 91麻豆精品国产自产在线观看亚洲| 又黄又爽又成人免费视频| 好吊色永久免费视频大全| 亚洲色在线无码国产精品不卡| 亚洲大尺度无码无码专区| 波多野结衣中文一区二区免费| 免费成人福利视频| a毛看片免费观看视频| 国产午夜亚洲精品不卡| 久久精品国产亚洲AV蜜臀色欲 | 国产偷v国产偷v亚洲高清| 美女被免费视频网站a国产| 57pao国产成视频免费播放| 久久久久久久久久久免费精品| 亚洲啪AV永久无码精品放毛片| 在线观看亚洲人成网站| 国产成人亚洲精品狼色在线| 国产高清在线精品免费软件| 和日本免费不卡在线v| 99免费在线观看视频| 男女一边桶一边摸一边脱视频免费 | 日本亚洲免费无线码| 久久大香伊焦在人线免费| 一个人看的免费高清视频日本| 亚洲欧美日韩自偷自拍|