【永恒的瞬間】
          ?Give me hapy ?
           

          Message-driven Bean

          Message-driven Bean是EJB2.0 規(guī)范中提出的的Enterprise Bean

          Message-driven Bean 的產(chǎn)生原因

          效率原因

          在JavaEE™平臺中,客戶端對Session Bean 和Entity Bean 的方法調(diào)用通過RMI或RMI-IIOP協(xié)議進行,這是傳統(tǒng)的通過網(wǎng)絡(luò)進行遠程調(diào)用的方法,當調(diào)用請求通過網(wǎng)絡(luò)傳播到容器,容器則將客戶端請求變成一序列的方法調(diào)用依次進行。客戶端只有在容器處理完請求并返回結(jié)果后方可繼續(xù)進行。

          可靠性的原因

          當客戶端對Session Bean或Entity Bean進行調(diào)用時,必須保證服務(wù)器容器處于運行狀態(tài),如容器或網(wǎng)絡(luò)出現(xiàn)錯誤,客戶端調(diào)用將無法進行。

          事件的廣播

          傳統(tǒng)的RMI 或RMI-IIOP機制中,客戶端在某一時刻只能與某一具體的服務(wù)器通訊, 沒有任何內(nèi)置的機制來將事件廣播到多個服務(wù)器。

          Message-driven Bean作為遠程方法調(diào)用的一種替代方法,在客戶端和服務(wù)器的直接方法調(diào)用之間放置了一個中間層,接收一個或多個客戶端的消息,并將消息轉(zhuǎn)發(fā)給一個或多個消息的使用者(Message Consumer)。

          通過消息機制而非直接的方法調(diào)用,客戶端可以繼續(xù)執(zhí)行而不必等待服務(wù)器的運行結(jié)果,服務(wù)器可以選擇在方法調(diào)用完成后通知客戶,而消息機制本身保證了信息傳輸?shù)目煽啃裕瑫r使用消息域(Message Domain)中的消息類型模型以達到事件廣播的機制。

          但是,對Message-Driven Bean 的使用也有一定的限制,如不適用于依賴于方法調(diào)用、要求具有明確的返回值才能繼續(xù)的客戶端程序。另外,如果在一個應(yīng)用中過多的使用了Message-Driven Bean, 對應(yīng)用的執(zhí)行效率將會產(chǎn)生影響,所以不適用于對時間因素敏感的客戶端程序(如在下午兩點定購下午四點的機票,而在四點后才得到訂購是否成功的結(jié)果,這時結(jié)果已毫無用處)。

          Message-driven Bean 作為一般的JMS 使用者(consumer)

          作為一種具有JMS使用者(consumer)功能的Enterprise Bean組件模型,Message-Driven Bean由EJB容器進行管理,具有一般的JMS使用者(consumer)所不具有的優(yōu)點,如對于一個Message-driven Bean,容器可創(chuàng)建多個實例來處理大量的并發(fā)消息,而一般的JMS使用者 (consumer)開發(fā)時則必須對此進行處理才能獲得類似的功能。同時Message-Driven Bean可取得EJB所能獲得的標準服務(wù),如容器管理事務(wù)等服務(wù)。

          由于與Message-driven Bean相關(guān)的主題(Topic)或隊列(Queue)可以在部署時配置,因此,Message-driven Bean具有更多的靈活性。

          但注意,一個Message-driven Bean在部署時只可與一個具體的主題(Topic)或隊列(Queue) 建立關(guān)聯(lián)。如有多個主題(Topic)或隊列(Queue)需要與一個Message-driven Bean關(guān)聯(lián),則 可以在部署時部署多個Message-driven Bean類,或使用一般的JMS使用者(consumer) 。

          Message-driven Bean 與其他Enterprise Bean

          作為Enterprise Bean組件模型之一,Message-driven Bean,具有一些與Session Bean 和Entity Bean相同的方法,但由于Message-driven Bean本身不處理客戶端調(diào)用,也無會話狀態(tài),客戶只能通過向與Message Driven Bean關(guān)聯(lián)的隊列或主題發(fā)送消息從而與Message-driven Bean 進行交互,因此,Message-driven Bean 與Session Bean 和Entity Bean之間最大的不同之處在于Message-Driven Bean不具有組件接口及Home接口。

          另外,Message-driven Bean異步地處理隊列(Queue)或主題(Topic)中的消息,而非方法調(diào)用。

          Message-driven Bean

          Message-driven BeanJMS消息驅(qū)動的JavaEE™平臺服務(wù)器端組件,具備無狀態(tài)、支持事務(wù)的特點。當從JMS隊列(Queue)或主題(Topic)中接收到JMS消息后,由容器對組件進行調(diào)用。一般,可理解為消息的監(jiān)聽器(Listener)及接收者(Consumer)。

          Message-driven Bean組件對于客戶端是不可見的。客戶端如希望調(diào)用封裝在組件中的業(yè)務(wù)邏輯,只能通過向組件監(jiān)聽的JMS隊列(Queue)或主題(Topic)發(fā)送消息,然后容器以事件的形式向組件實例發(fā)送消息,組件實例根據(jù)消息的內(nèi)容調(diào)用相應(yīng)的業(yè)務(wù)邏輯或其他組件。

          因此,任何向組件監(jiān)聽的特定JMS隊列(Queue)或主題(Topic)發(fā)送JMS消息的客戶端,即可視為Message-driven Bean的客戶端。

          Message-driven Bean組件模型不具備會話狀態(tài),也就是說,當組件實例在沒有對客戶端的JMS消息提供處理的時候,所有的實例間沒有差別。

          Message-driven Bean的運行和客戶端的運行是異步的。同時,對于客戶端不可見。其實例由容器創(chuàng)建,其生存周期由容器控制。

          Message-driven BeanEJB容器、客戶端、消息系統(tǒng)

          下圖是EJB容器、客戶端、消息系統(tǒng)與EJB之間的關(guān)系:

          EJB容器、客戶端、消息系統(tǒng)與EJB之間的關(guān)系

          客戶端發(fā)送消息到JMS消息系統(tǒng)中的隊列或主題。Message-driven Bean在部署到容器中時,指定的隊列或主題,容器對其進行監(jiān)聽;當容器從隊列或主題中接收到消息之后,將消息作為事件的一部分通知容器中相應(yīng)的Message-driven Bean實例。

          組件模型單元

          Message-driven Bean由容器控制其生存周期,容器提供安全、并發(fā)、事務(wù)等等服務(wù),對于客戶端來說,Message-driven Bean是不可見的。因此,Message-driven Bean不同于Session BeanEntity Bean,不具有組件接口和Home接口。

          Message-driven Bean組件模型包含兩個單元,即組件類和部署描述。下面分別對開發(fā)這些單元時,涉及的普遍過程、規(guī)則及注意事項進行描述。

          組件類

           javax.ejb.MessageDrivenBean接口

          EJB2.1規(guī)范中的Message-driven Bean組件中的組件類必須實現(xiàn)MessageDrivenBean接口。EJB3.0規(guī)范不強制Message-driven Bean實現(xiàn)該接口,而通過@MessageDriven注解進行標記并通過依賴注入與注解實現(xiàn)類似功能。

          MessageDrivenBean接口中定義了兩個容器管理回調(diào)的方法:

          ·             setMessageDrivenContext方法,容器創(chuàng)建Bean實例后,容器將調(diào)用該方法將由容器維護的Bean實例的上下文(context)與Bean實例進行關(guān)聯(lián)。EJB3.0規(guī)范中,可使用@Resource注解通知容器注入MessageDrivenContext實例。

          ·             ejbRemove方法,在實例被容器清除時,容器將調(diào)用此方法。一般,實例會在此方法中對實例占用的資源進行釋放。在EJB3.0規(guī)范中,可使用@PreDestroy注解標記此方法。

           javax.jms.MessageListener接口

          Message-driven Bean組件中的組件類必須實現(xiàn)MessageListener接口。

          在消息到達Message-driven Bean指定的監(jiān)聽隊列或主題時,容器將調(diào)用javax.jms.MessageListener接口中定義的onMessage方法。開發(fā)者在此方法中提供對消息進行處理的業(yè)務(wù)邏輯。

          Session BeanEntity Bean不可實現(xiàn)javax.jms.MessageListener接口。

           javax.ejb.MessageDrivenContext接口

          容器將提供一個MessageDrivenContext對象,使實例可以訪問由容器維護的實例的上下文環(huán)境。在此接口中,定義了如下方法:

          ·             getEJBHomegetEJBLocalHome方法,從EJBContext接口繼承的方法,Message-driven Bean實例不可調(diào)用此方法;

          ·             getCallerPrincipal方法,從EJBContext接口繼承的方法,Message-driven Bean實例不可調(diào)用此方法;

          ·             isCallerInRole方法,從EJBContext接口繼承的方法,Message-driven Bean實例不可調(diào)用此方法;

          ·             setRollbackOnly方法,當前事務(wù)將被永久標記為回滾,不會被提交。只有容器管理事務(wù)的Message-driven Bean可被允許使用此方法;

          ·             getRollbackOnly方法,檢查當前事務(wù)是否已被標記為回滾。例如,EJB實例可以通過此方法,決定是否繼續(xù)在當前事務(wù)邊界內(nèi)繼續(xù)進行計算。只有容器管理事務(wù)的Message-driven Bean可被允許使用此方法;

          ·             getUserTransaction方法,返回javax.transaction.UserTransaction接口。EJB實例可通過此接口對事務(wù)邊界進行劃分,并取得事務(wù)的狀態(tài)。只有容器管理事務(wù)的Message-driven Bean可被允許使用此方法;

           串行化的調(diào)用

          Apusic應(yīng)用服務(wù)器中的EJB容器支持Message-driven Bean的多個實例的并發(fā)運行,但是每個實例只看到一個串行的方法調(diào)用過程,因此開發(fā)Message-driven Bean時,不需要將其以可重入(reentrant)的方式進行編寫。

           消息處理的并發(fā)

          Apusic應(yīng)用服務(wù)器允許Message-driven Bean的多個實例并發(fā)執(zhí)行,提供對流(Stream)消息并發(fā)處理。

           Message-driven Bean方法的事務(wù)上下文

          onMessage方法在何種事務(wù)范圍內(nèi)被調(diào)用,取決于部署描述中指定的事物屬性,如Bean被指定使用容器管理的事務(wù)的方式,則必須將事務(wù)屬性設(shè)置為“Required”“NotSupported”

          Bean采用Bean管理的事務(wù)的方式,即使用javax.transaction.UserTransaction接口進行事務(wù)劃分時,導致Bean實例被調(diào)用的消息接收操作并非是事務(wù)中的一部分。如果希望消息接收操作是事務(wù)中的一部分,則Bean必須使用容器管理事務(wù)的方式,并且設(shè)置事務(wù)屬性為“Required”

           消息接收確認(Message Acknowledgement

          Message-driven Bean不能使用JMS API中提供的消息接收確認操作。消息接收確認操作由容器自動完成。如Bean采用了容器管理事務(wù)的方式,則消息接收確認操作作為事務(wù)提交的一部分自動進行。如使用了Bean管理事務(wù)的方式,消息接收確認操作不能作為事務(wù)提交的一部分,開發(fā)者可通過在部署描述中的acknowledge-mode元素指定消息接收確認操作的方式為AUTO_ACKNOWLEDGEDUPS_OK_ACKNOWLEDGE,如未指定acknowledge-mode元素,容器將使用AUTO_ACKNOWLEDGE方式進行消息接收確認操作。

          指定隊列(Queue)或主題(Topic

          Message-driven Bean被部署到容器時,必須關(guān)聯(lián)到某個消息隊列(Queue)或主題(Topic),以便容器對此隊列或主題進行監(jiān)聽。

          開發(fā)者可通過@MessageDriven注解的mappedName屬性或部署描述文件中的message-driven-destination元素指定關(guān)聯(lián)的隊列或主題。

          Bean關(guān)聯(lián)的是一個消息主題,則通過部署描述中的subscription-durability元素指定對隊列進行的是持久還是非持久訂閱,如此元素未指定,則使用非持久訂閱的方式。

           異常處理

          Message-driven Bean中的onMessage方法不能聲明拋出java.rmi.RemoteException異常。

          一般來說,Message-driven Bean在運行期間不應(yīng)向容器拋出RuntimeException異常。RuntimeException異常是指會導致Message-driven Bean進入不存在狀態(tài)的非應(yīng)用級異常。如果Bean使用了Bean-managed事務(wù)并拋出了RuntimeException異常,容器不應(yīng)確認收到了這條消息。

          從發(fā)信端看來,收信端一直存在,若發(fā)信端繼續(xù)對該目的地發(fā)送消息,容器會自動把消息轉(zhuǎn)向到其他Message-driven Bean實例。

          遺漏的PreDestroy調(diào)用

          在系統(tǒng)發(fā)生異常的情況下,不能保證容器總會調(diào)用BeanPreDestroy方法,因此,如果BeanPostConstruct方法中打開了一些資源,并在PreDestroy方法中釋放這些資源,在這種情況下,則這些資源不能被釋放。

          鑒于以上原因,使用Message-driven Bean的應(yīng)用需要提供一種機制,以便周期性的清除這些未釋放的資源占用。

           必須遵守的規(guī)則

          在開發(fā)Message-driven Bean時,開發(fā)者必須遵守如下規(guī)則:

           組件類

          ·             使用EJB2.1規(guī)范時,必須間接或直接實現(xiàn)javax.ejb.MessageDrivenBean接口;使用EJB3.0規(guī)范時,可改為使用@MessageDriven注解對組件類進行標記。

          ·             必須間接或直接實現(xiàn)javax.jms.MessageListener接口;

          ·             類必須聲明為public,不可被聲明為finalabstract類;

          ·             必須擁有一個無參數(shù)的public構(gòu)造函數(shù)(constructor);

          ·             類不能定義finalize()方法;

          ·             在原EJB2.1規(guī)范中,類必須實現(xiàn)ejbCreate()方法用來創(chuàng)建組件實例,在EJB3.0中,這一要求已被移除了。EJB3.0的兼容規(guī)則規(guī)定,如果Message-driven Bean類實現(xiàn)了ejbCreate()方法,將看作被@PostConstruct注解標記的方法處理。此時若同時使用@PostConstruct注解,則只能標記ejbCreate()方法。

           onMessage方法

          ·             方法必須被聲明為public

          ·             方法不能被聲明為finalstatic

          ·             返回值必須為void

          ·             方法只能有一個javax.jms.Message類型的參數(shù);

          ·             不能拋出java.rmi.RemoteException異常

          ·             運行期間一般來說不應(yīng)拋出RuntimeException。請參考:

           ejbRemove方法

          ·             方法名必須是ejbRemove;

          ·             方法必須被聲明為public

          ·             方法不能被聲明為finalstatic

          ·             返回值必須為void

          ·             方法不能有參數(shù);

          ·             不能拋出java.rmi.RemoteException異常。

          ·             EJB3.0規(guī)范中,可使用@PreDestroy注解實現(xiàn)同樣效果。若實現(xiàn)javax.ejb.MessageDrivenBean接口同時使用注解,則只能把ejbRemove()方法注解為@PreDestroy

          生存周期

          下圖表示Message-driven Bean的生存周期。

          Message-driven Bean的生存周期

          posted on 2007-10-22 12:27 ???MengChuChen 閱讀(2709) 評論(0)  編輯  收藏 所屬分類: EJB3.0

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


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 丹凤县| 上犹县| 芦溪县| 银川市| 扎赉特旗| 田阳县| 晋州市| 恩施市| 榆树市| 丹江口市| 梁河县| 富川| 墨玉县| 桐乡市| 新田县| 那曲县| 寿阳县| 南陵县| 海林市| 仙游县| 衡山县| 蕲春县| 胶州市| 祁门县| 碌曲县| 崇信县| 崇左市| 马山县| 林西县| 大理市| 益阳市| 门头沟区| 儋州市| 嘉兴市| 吐鲁番市| 东明县| 疏勒县| 晋江市| 云浮市| 荔浦县| 合川市|