国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

深入探討EJB中新的消息驅動組件(一)

2019-11-18 14:47:41
字體:
來源:轉載
供稿:網友

  提要:我們可以使用MessageDrivenBean(消息驅動組件),在企業級的應用程序中進行異步的消息傳送。

  引言:EnterPRise javaBeans(EJB)1.1版本中定義了兩種組件類型?session組件和entity組件。客戶端對象可以同步調用EJB1.1的這兩種組件的方法,然而,為了繼續Message Oriented Middleware(MOM,面向對象的中間件)和Java Message Service(JMS,Java消息服務)的優點的需要,EJB框架中也相應的應當加入異步的消息通訊機制,所以,在EJB2.0中就定義了第三種組件類型----MessageDrivenBean(消息驅動組件)

  MessageDrivenBean兼備EJB和JMS的功能,當然,假如您想要消息操作技術,那么您大可只使用JMS就行了,但是新的消息驅動組件MessageDrivenBean提供了消息通訊的新的可能性。那么,這些組件如何整合到一個應用程序服務器框架中?他們的功能又如何擴大了過去JMS服務器的使用范圍?讓我們看下文吧!

  EJB和JMS

  前面我們已經說過了,EJB1.1種為開發者定義了兩個企業級組件類型-----session和entity組件。session組件通常實現一些商業邏輯并且不能在多客戶端共用。Entity組件則描述一個實體的面向對象的概念,而這個實體往往存在于像數據庫那樣固定的存儲容器中。在這兩種組件模型中,使用本地的或遠程的接口來簡化客戶端的交互作用。按照定義,這種交互作用是嚴格的同步的。舉例來說,通過一個方法調用把一個請求發送給組件,然后服務器對象返回一個響應。(如圖1),





然而,在企業版應用程序的范圍中,也經常需要異步的消息傳遞,比方說,一個客戶可能想發給服務器一條信息,但是并不需要或者不想要服務器做出應答,這時,客戶端就沒有必要等待服務器對象處理請求。對于客戶端應用程序來說,在確保消息最終能夠到達服務器并被正常處理的前提下,提交一條消息然后繼續處理本身的事務,將會在很大的程度上提高效率。

  能夠處理異步消息的能力的Java技術可以在Java Message Service(JMS)中找到,JMS原本就是被開發來提供傳統的Message Oriented Middleware(MOM)產品的一個標準Java接口。

  現在,一些公司開發出了一整套新一代輕量級高效的純Java的JMS產品,這些產品是開發者能夠建立JMS連接來發布或從其它應用程序組件中接受消息。下面的例程給出了與一個JMS提供者接口的必要步驟:

代碼段一:預備客戶端

  客戶端應用程序使用了帶有JMS 主題的MessageListener來接受和處理消息。

import javax.jms.*;

/**

*一個例程,演示如何取得一個JMS

*連接并取得一個消息監聽者。在本例中

*我們將獲取一個與一個JMS主題的連接

*/

public class JMSSample {

public static void main (String args[])

{

InitialContext context = new InitialContext();

// 查找主題

Topic topic (Topic)context.lookup("MyTopic");

file://取得我們創建JMS連接時所要用到的連接創建器

TopicConnectionFactory tcf =

(TopicConnectionFactory)context.lookup(

"TopicConnectionFactory");

// 創建JMS連接

TopicConnection conn = tcf.createTopicConnection();

// 從連接中創建JMS session。

// 這樣我們就可以創建一個非事務處理、AUTO_ACKNOWLEDGE的連接

TopicSession session = conn.createTopicSession(

false, Session.AUTO_ACKNOWLEDGE);

// 創建主題訂閱者

TopicSubscriber subscriber =

session.createSubscriber(topic);

// 監聽者

subscriber.setMessageListener(myListener);



// 指出我們將要接受信息的連接

conn.start();

}

}


  除了采用上面的步驟取得JMS MessageConsumer(消息消費者)的連接之外,開發者還可創建并注冊一個或多個使用Message Consumer的JMS Message Listener(消息監聽者)接口。Message Listener總是在一個單獨的控制線程中執行,這就意味著在編寫消息監聽者時,開發者不需要擔心并發性問題的出現,見圖2。




下面我給出了一個典型的JMS 消息監聽者實現的代碼。

  代碼段2:

/**

* 這個類是JMS MessageListener的一個實現

* 用來處理包含股票報價的消息

*/

class MyListener implements MessageListener {

/**

* 從收到的信息中取出股票報價

* 并且把它放入標準輸出流中并顯示。

*/

public void onMessage(Message message) {

// 從消息對象中取出報價

// 我們知道消息產生者發送TextMessages

try

{

String quote = ((TextMessage)message).getText();

System.out.println("股票報價: " + quote);

}

catch(JMSException e)

{

System.out.println(

"錯誤處理消息: "+message);

}

}

}


  在這個實現中,MessageListener接收到的消息中包含了股票報價,消息監聽者只是簡單的從消息體中取得股票報價并把它輸出到標準輸出流中。

  開發一個健壯的JMS客戶端程序可能是非常困難的,程序員必須要考慮可能會同時接受多個消息,此外還有交易安全性、并發性消息處理、對象生命周期、容錯性和可擴展性,這些都是開發者急切地想從EJB服務器中找到的功能。不過直到現在,程序員們還不得不自己動手把這些技術結合在一起應用。

  為了整合EJB1.1和JMS,JMS監聽者必須要使用我們在代碼段2中描述的方法來建立。JMS客戶端程序必須參考一個stateless(無狀態)的用于響應處理JMS消息的session組件,然后,JMS消息要傳遞給EJB。然而,JMS消息并不要求被序列化,這就意味著這條消息在傳遞到遠程的EJB實例之前必須被轉換成為有序的消息類或在消息監聽者中部分地解構。而且,應用程序開發者還有責任治理JMS服務器之間的事務聯系,以及處理EJB、消息和并發性,這些都是非常復雜的事情。

  即使一個應用程序開發者能把上面的這些都完成,并且也有能力訪問JMS提供者并取得消息,但顯然,他需要編寫一大堆的代碼,這對于我們這些常人往往是不大可能實現的。EJB2.0解決了這個問題,它通過擴展EJB組件類型,為需要異步消息支持的組件開發者提供簡化的解決方案??新的MessageDriven組件類型。

MessageDrivenBean組件

  MessageDrivenBean被部署成為總是扮演信息消費者角色的客戶端。MessageDrivenBean沒有客戶端視圖,這就意味著其本地和遠程調用接口都是不可用的。一個消息產生者發信息給一個主題或隊列并且沒有熟悉到一個事實--MessageDrivenBean正扮演著消息消費者的身份。這就導致了在基于系統的 JMS之間的寬松聯結,并更多的考慮到了在集合一個分布式計算環境時應有的靈活性。

  MessageDriven 組件沒有對話狀態,其實所有的組件實例當它們在沒有處理消息時都是等價的。這有點和無狀態的session組件的狀態特征有些類似。把組件實例集中起來是治理MessageDriven組件實例的普遍而又有效的辦法。

  MessageDriven 組件必須以直接或間接的方法從接口javax.ejb.MessageDrivenBean中取得,而這個接口類則是從javax.jms.MessageListener接口得來并添加了兩個方法。onMessage()方法是從javax.jms.MessageListener接口中繼續來的,這個方法有唯一的參數,就是javax.jms.Message,可以是任何有效的JMS消息類型。這個方法顯然不包括throw(拋出)子句,所以在處理消息時不會拋出任何應用程序異常。

當這個容器接收到消息,它首先從一個可用實例池中取得一個MessageDriven組件(見圖4)然后把部署描述器中制定的任務與執行線程聯系起來,使其能夠傳播安全上下文。此外,假如部署描述器需要事務上下文的話,容器也會設置與之的關聯。





  一旦完成了治理任務,接收到的消息酒杯傳送到MessageDrivenBean實例的onMessage()方法中,而一旦這個方法完成后,消息所載的事務就會被執行或返回,然后組件重新返回可用實例池中。

  當MessageDrivenBean實例被從容器中(通常從實例池中)的任何強的參考中逐出,都會調用ejbRemove()方法。ejbRemove()方法將釋放任何被組件實例占用的資源。setMessageDrivenContext()方法有一個參數--javax.ejb.MessageDrivenContext類的一個實例。MessageDrivenContext類與定義在EJB1.1中的entity和session類有點類似,當一個組件實例被創建,容器就把它傳遞進一個實例占用的上下文中,這個類有取得環境信息的方法也有相應的方法取得JTA UserTransaction類(用于治理事務定界的組件)。

  此外,組件提供者還應當在EJB2.0服務器中可攝制的組件提供一個沒有參數的ejb.Create()方法。這個組件實例可以獲得任何在ejb.Create()用于進行處理的所需要的資源,比如說,在這一點上,MessageDrivenBean實例可以取得一個數據庫連接,假如ejb.Remove()方法被調用的話,它將關閉或釋放。

  值得注重的是,MessageDrivenBean現在已經大大的簡化了創建JMS消息消費者的過程,下面的代碼段3就創建并配置了一個EJB容器所委托創建的JMS消息消費者。開發者現在可以很輕易的實現MessageDrivenBean接口,并可以把它配置在EJB服務器中且可以用來創建一個可收集消息的商業組件。

  代碼段3:

/**

*MessageDrivenBean接口由每一個消息驅動企業級組件類實現。

*這個容器使用MessageDrivenBean 方法來通知

*企業級Bean實例的實例生命周期事件

*/



public interface javax.ejb.MessageDrivenBean extends

javax.jms.MessageListener

{

/**

* 傳送一個消息給監聽者

*

* 參數 message :Message對象。

*/

public void onMessage(javax.jms.Message message);

/**

*容器在結束消息驅動對象的生命周期之前,調用這個方法。

*/

public void ejbRemove();



/**

*設置相關聯的消息驅動上下文。

*容器在創建了實例后調用這個方法。

* 企業版 Bean 實例將保存context對象的參考到一個實例對象中

*/

public void

setMessageDrivenContext(

javax.ejb.MessageDrivenContext context);

}


  在代碼段4中給出了一個MessageDrivenBean實例的實現,在個組件從一個JMS TextMessage中取得一條字符串,并輸出,它是根據代碼段2種的JMS消息監聽者程序改編的。

  代碼段: 4

/**

* 這個類是 MessageDrivenBean的一個實現。

*/



public class MyListenerMDB implements MessageDrivenBean

{

/**

* 這是一個無參數構造器,這樣 EJB容器可以使用Class.newInstance()方法來創建組件實例

*/

public MyListenerMDB()

{

}

/**

*這個方法接受消息實例并執行消息處理過程。

*

* 參數:message 。Message對象

*/

public void onMessage(Message message)

{

// onMessage 實現仍然未變:

// 從message對象中取出股票報價。

// StockQuoteProdUCer 發送 TextMessages

// 并在適合的時候放出該對象。

try

{

String quote = ((TextMessage)message).getText();

System.out.println("股票報價: " + quote);

}

catch(JMSException e)

{

System.out.println(

"不能處理消息: " + message);

}

}



/**

* 當MessageDrivenBean實例被從容器中拋出,該方法就被調用。

*/

public void ejbRemove() throws javax.ejb.EJBException

{

System.out.println(

"StockListenerMDB: ejbRemove被調用。");

}



/**

* 設置MessageDrivenContext實例。本方法將在組件實例化時被調用

*消息驅動上下文答應組件開發者訪問EJB容器的工具

*

* 參數ctx : 消息驅動上下文

*/

public void setMessageDrivenContext(

MessageDrivenContext ctx) throws javax.ejb.EJBException

{

System.out.println(

"StockListenerMDB: setMessageDrivenContext 被調用。");

}



/**

* ejbCreate with no args required by spec, though not

* enforced by interface

*/

public void ejbCreate()

{

System.out.println(

"StockListenerMDB: ejbCreate called.");

}

}


  部署描述器

  MessageDrivenBean可以使用xml部署描述器來指出受EJB服務器信息控制的運行時間動作,下面是部署描述器中定義MessageDrivenBean的有效的DTD元素。

<!ELEMENT message-driven (description?,

display-name?, small-icon?,

large-icon?, ejb-name?, ejb-class,

transaction-type, transaction-scope?,

jms-message-selector?, jms-acknowledge-

mode?, message-driven-destination?,

env-entry*, ejb-ref*, security-

identity?, resource-ref*, resource-

env-ref*)>




  需要注重的是,部署描述器包含所有除用來部署MessageDrivenBean組件的目標名以外的所有信息,目標名被設置在一個應用程序服務器提供商指定的配置文件中或作為一個系統屬性。

  在部署描述器中,配置器可以指定組件是傾向于用于主題還是用于隊列,并且,假如傾向于用于主題那么組件是否應該擔當持久的簽署者( durable subscriber)的身份。像隊列一樣,持久的主題保證監聽者將接收到所有發布到這個主題的消息,即使監聽者可能一段時間都不可用。 持久的主題對應用程序的可靠性很重要。

  我們的給出的MessageDrivenBean的部署描述器(見代碼段5)告訴容器這個組件是特意偵聽一個不持久主題。這個組件有使用 NotSupported方法事務屬性的容器治理事務限定。

  代碼段5:

<ejb-jar>
<enterprise-beans>
<message-driven>
<ejb-name>MessageListenerMDB</ejb-name>
<ejb-class>messageListenerMDB</ejb-class>
<transaction-type>Container</transaction-type>
<transaction-scope>Local</transaction-scope>
<jms-acknowledge-mode>auto-acknowledge</jms-
acknowledge-mode>
<message-driven-destination>
<jms-destination-type>javax.jms.Topic</jms-
destination-type>
<jms-subscription-durability>nondurable</jms-
subscription-durability>
</message-driven-destination>
</message-driven>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>MessageListenerMDB</ejb-name>
<method-name>onMessage</method-name>
<method-params>
<method-param>javax.jms.Message</method-param>
</method-params>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>


  使用MessageDrivenBean組件的另一個好處就是它的部署的簡潔性。 典型情況下,一個應用服務器供給商將提供定義組件部署描述器的工具,產生 EJB jar文件,并且部署組件。 一旦組件部署好了, EJB服務器將處理 EJB容器類的注冊并且開始 JMS連接。 因為 JMS定義了一個標準,一個基于 JNDI的機制,用于獲得 JMS主題,隊列,連接以及一個能夠使用任何JMS供給商實現的高端的應用程序服務器的引用。 這答應設計者在開發商業程序時最充分的利用應用程序服務器和JMS服務器。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 巴中市| 北流市| 辰溪县| 武邑县| 杭锦旗| 阿巴嘎旗| 石嘴山市| 湘潭县| 峨山| 休宁县| 绥阳县| 英德市| 湖南省| 民权县| 尚志市| 延边| 南郑县| 博罗县| 奉节县| 望奎县| 甘德县| 吉林市| 大姚县| 基隆市| 长乐市| 天柱县| 庆城县| 巩留县| 德令哈市| 且末县| 台东县| 郁南县| 综艺| 大理市| 微山县| 冀州市| 肇庆市| 大新县| 塔河县| 通山县| 绵竹市|