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

          Message-driven Bean

          Message-driven Bean是EJB2.0 規范中提出的的Enterprise Bean

          Message-driven Bean 的產生原因

          效率原因

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

          可靠性的原因

          當客戶端對Session Bean或Entity Bean進行調用時,必須保證服務器容器處于運行狀態,如容器或網絡出現錯誤,客戶端調用將無法進行。

          事件的廣播

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

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

          通過消息機制而非直接的方法調用,客戶端可以繼續執行而不必等待服務器的運行結果,服務器可以選擇在方法調用完成后通知客戶,而消息機制本身保證了信息傳輸的可靠性,同時使用消息域(Message Domain)中的消息類型模型以達到事件廣播的機制。

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

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

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

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

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

          Message-driven Bean 與其他Enterprise Bean

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

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

          Message-driven Bean

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

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

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

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

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

          Message-driven BeanEJB容器、客戶端、消息系統

          下圖是EJB容器、客戶端、消息系統與EJB之間的關系:

          EJB容器、客戶端、消息系統與EJB之間的關系

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

          組件模型單元

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

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

          組件類

           javax.ejb.MessageDrivenBean接口

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

          MessageDrivenBean接口中定義了兩個容器管理回調的方法:

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

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

           javax.jms.MessageListener接口

          Message-driven Bean組件中的組件類必須實現MessageListener接口。

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

          Session BeanEntity Bean不可實現javax.jms.MessageListener接口。

           javax.ejb.MessageDrivenContext接口

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

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

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

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

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

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

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

           串行化的調用

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

           消息處理的并發

          Apusic應用服務器允許Message-driven Bean的多個實例并發執行,提供對流(Stream)消息并發處理。

           Message-driven Bean方法的事務上下文

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

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

           消息接收確認(Message Acknowledgement

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

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

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

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

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

           異常處理

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

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

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

          遺漏的PreDestroy調用

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

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

           必須遵守的規則

          在開發Message-driven Bean時,開發者必須遵守如下規則:

           組件類

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

          ·             必須間接或直接實現javax.jms.MessageListener接口;

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

          ·             必須擁有一個無參數的public構造函數(constructor);

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

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

           onMessage方法

          ·             方法必須被聲明為public

          ·             方法不能被聲明為finalstatic

          ·             返回值必須為void

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

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

          ·             運行期間一般來說不應拋出RuntimeException。請參考:

           ejbRemove方法

          ·             方法名必須是ejbRemove;

          ·             方法必須被聲明為public

          ·             方法不能被聲明為finalstatic

          ·             返回值必須為void

          ·             方法不能有參數;

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

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

          生存周期

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

          Message-driven Bean的生存周期

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

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


          網站導航:
           
          主站蜘蛛池模板: 灵丘县| 叶城县| 四会市| 太康县| 普兰县| 都匀市| 白城市| 丁青县| 大邑县| 乌拉特后旗| 武隆县| 南康市| 岐山县| 通州市| 仙游县| 新田县| 海南省| 北碚区| 龙山县| 息烽县| 四会市| 黑水县| 通许县| 宁化县| 二手房| 阿鲁科尔沁旗| 德格县| 定远县| 泌阳县| 邯郸县| 嘉峪关市| 湄潭县| 高青县| 喀什市| 河源市| 柞水县| 丹东市| 开封市| 广宗县| 惠来县| 宁陕县|