日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Spring - Java/J2EE Application Framework 应用框架 第 15 章 EJB的存取和实现

發(fā)布時(shí)間:2025/3/21 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring - Java/J2EE Application Framework 应用框架 第 15 章 EJB的存取和实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第?15?章?EJB的存取和實(shí)現(xiàn)

作為輕量級的容器,Spring常常被認(rèn)為是EJB的替代品。我們也相信,對于很多 (不一定是絕大多數(shù))應(yīng)用和用例,相對于通過EJB容器來實(shí)現(xiàn)相同的功能而言, Sping作為容器,加上它在事務(wù),ORM和JDBC存取這些領(lǐng)域中豐富的功能支持, Spring的確是更好的選擇。

不過,需要特別注意的是,使用了Spring并不是說我們就不能用EJB了, 實(shí)際上,Spring大大簡化了從中訪問和實(shí)現(xiàn)EJB組件或只實(shí)現(xiàn)(EJB組件)其功能的復(fù)雜性。 另外,如果通過Spring來訪問EJB組件服務(wù),以后就可以在本地EJB組件,遠(yuǎn)程EJB組件, 或者是POJO(簡單Java對象)這些變體之間透明地切換服務(wù)的實(shí)現(xiàn),而不需要修改 客戶端的代碼。

本章,我們來看看Spring是如何幫助我們訪問和實(shí)現(xiàn)EJB組件的。尤其是在訪問 無狀態(tài)Session Bean(SLSBs)的時(shí)候,Spring特別有用,現(xiàn)在我們就由此開始討論。

15.1.?訪問EJB

15.1.1.?概念

要調(diào)用本地或遠(yuǎn)程無狀態(tài)Session Bean上的方法,通常客戶端的代碼必須 進(jìn)行JNDI查找,得到(本地或遠(yuǎn)程的)EJB Home對象,然后調(diào)用該對象的"create" 方法,才能得到實(shí)際的(本地或遠(yuǎn)程的)EJB對象。前后調(diào)用了不止一個(gè)EJB組件 上的方法。

為了避免重復(fù)的底層調(diào)用,很多EJB應(yīng)用使用了服務(wù)定位器(Service Locator) 和業(yè)務(wù)委托(Bussiness Delegate)模式,這樣要比在客戶端代碼中到處進(jìn)行JNDI 查找更好些,不過它們的常見的實(shí)現(xiàn)都有明顯的缺陷。例如:

  • 通常,若是依賴于服務(wù)定位器或業(yè)務(wù)代理單件來使用EJB,則很難對代碼進(jìn) 行測試。

  • 在僅使用了服務(wù)定位器模式而不使用業(yè)務(wù)委托模式的情況下,應(yīng)用程序 代碼仍然需要調(diào)用EJB Home組件的create方法,還是要處理由此引入的異常。 導(dǎo)致代碼仍然保留了與EJB API的耦合性以及EJB編程模型的復(fù)雜性。

  • 實(shí)現(xiàn)業(yè)務(wù)委托模式通常會(huì)導(dǎo)致大量的冗余代碼,因?yàn)槲覀儾坏貌痪帉?很多方法,而它們所做的僅僅是調(diào)用EJB組件的同名方法。

Spring采用的方法是允許創(chuàng)建并使用代理對象,一般是在Spring的 ApplicationContext或BeanFactory里面進(jìn)行配置,這樣就和業(yè)務(wù)代理類似,只需要 少量的代碼。我們不再需要另外編寫額外的服務(wù)定位器或JNDI查找的代碼,或者是手寫 的業(yè)務(wù)委托對象里面冗余的方法,除非它們可以帶來實(shí)質(zhì)性的好處。

15.1.2.?訪問本地的無狀態(tài)Session Bean(SLSB)

假設(shè)有一個(gè)web控制器需要使用本地EJB組件。我們遵循前人的實(shí)踐經(jīng)驗(yàn), 于是使用了EJB的業(yè)務(wù)方法接口(Business Methods Interface)模式,這樣, 這個(gè)EJB組件的本地接口就擴(kuò)展了非EJB特定的業(yè)務(wù)方法接口。讓我們假定這個(gè) 業(yè)務(wù)方法接口叫MyComponent。

public interface MyComponent {... }

(使用業(yè)務(wù)方法接口模式的一個(gè)主要原因就是為了保證本地接口和bean的實(shí)現(xiàn)類 之間方法簽名的同步是自動(dòng)的。另外一個(gè)原因是它使得稍后我們改用基于POJO(簡單Java對象) 的服務(wù)實(shí)現(xiàn)更加容易,只要這樣的改變是有利的。當(dāng)然,我們也需要實(shí)現(xiàn) 本地Home接口,并提供一個(gè)Bean實(shí)現(xiàn)類,使其實(shí)現(xiàn)接口SessionBean和業(yè)務(wù)方法接口 MyComponent。現(xiàn)在為了把我們Web層的控制器和EJB的實(shí)現(xiàn)鏈接起來,我們唯一要寫 的Java代碼就是在控制器上公布一個(gè)形參為MyComponent的setter方法。這樣就可以 把這個(gè)引用保存在控制器的一個(gè)實(shí)例變量中。

private MyComponent myComponent;public void setMyComponent(MyComponent myComponent) {this.myComponent = myComponent; }

然后我們可以在控制器的任意業(yè)務(wù)方法里面使用這個(gè)實(shí)例變量。假設(shè)我們現(xiàn)在 從Spring的ApplicationContext或BeanFactory獲得該控制器對象,我們就可以在 同一個(gè)上下文中配置一個(gè)LocalStatelessSessionProxyFactoryBean?的實(shí)例,它將作為EJB組件的代理對象。這個(gè)代理對象的配置和控制器的屬性?myComponent的設(shè)置是使用一個(gè)配置項(xiàng)完成的,如下所示:

<bean id="myComponent"class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean"><property name="jndiName"><value>myComponent</value></property><property name="businessInterface"><value>com.mycom.MyComponent</value></property> </bean><bean id="myController" class = "com.mycom.myController"><property name="myComponent"><ref bean="myComponent"/></property> </bean>

這些看似簡單的代碼背后隱藏了很多復(fù)雜的處理,比如默默工作的Spring AOP框架,我們甚至不必知道這些概念,一樣可以享用它的結(jié)果。Bean?myComponent?的定義中創(chuàng)建了一個(gè)該EJB組件的代理對象,它實(shí)現(xiàn)了業(yè)務(wù)方法接口。這個(gè)EJB組件的 本地Home對象在啟動(dòng)的時(shí)候就被放到了緩存中,所以只需要執(zhí)行一次JNDI查找即可。 每當(dāng)EJB組件被調(diào)用的時(shí)候,這個(gè)代理對象就調(diào)用本地EJB組件的create方法,并調(diào)用 該EJB組件的相應(yīng)的業(yè)務(wù)方法。

在Bean?myController的定義中,控制器類的屬性?myController的值被設(shè)置為上面代理對象。

這樣的EJB組件訪問方式大大簡化了應(yīng)用程序代碼:Web層(或其他EJB客戶端) 的代碼不再依賴于EJB組件的使用。如果我們想把這個(gè)EJB的引用替換為一個(gè)POJO, 或者是模擬用的對象或其他測試組件,我們只需要簡單地修改Bean?myComponent?的定義中僅僅一行Java代碼,此外,我們也不再需要在應(yīng)用程序中編寫任何JNDI查找 或其它EJB相關(guān)的代碼。

評測和實(shí)際應(yīng)用中的經(jīng)驗(yàn)表明,這種方式的性能負(fù)荷極小,(盡管其中 使用了反射方式以調(diào)用目標(biāo)EJB組件的方法),通常的使用中我們幾乎覺察不出。請記住 我們并不想頻繁地調(diào)用EJB組件的底層方法,雖然如此,有些性能代價(jià)是與應(yīng)用服務(wù)器 中EJB的基礎(chǔ)框架相關(guān)的。

關(guān)于JNDI查找有一點(diǎn)需要注意。在Bean容器中,這個(gè)類通常最好用作單件 (沒理由使之成為原型)。不過,如果這個(gè)Bean容器會(huì)預(yù)先實(shí)例化單件(類似XML ApplicationContext的變體的行為),如果在EJB容器載入目標(biāo)EJB前載入bean容器, 我們就可能會(huì)遇到問題。因?yàn)镴NDI查找會(huì)在該類的init方法中被執(zhí)行并且緩存結(jié)果, 這樣就導(dǎo)致該EJB不能被綁定到目標(biāo)位置。解決方案就是不要預(yù)先實(shí)例化這個(gè)工廠對象, 而允許它在第一次用到的時(shí)候再創(chuàng)建,在XML容器中,這是通過屬性?lazy-init來控制的。

盡管大部分Spring的用戶不會(huì)對這些感興趣,但那些對EJB進(jìn)行AOP的具體應(yīng)用 的用戶則會(huì)想看看LocalSlsbInvokerInterceptor。

15.1.3.?訪問遠(yuǎn)程的無狀態(tài)Session Bean(SLSB)

基本上訪問遠(yuǎn)程EJB與訪問本地EJB差別不大,除了前者使用的是?SimpleRemoteStatelessSessionProxyFactoryBean。當(dāng)然, 無論是否使用Spring,遠(yuǎn)程調(diào)用的語義都相同,不過,對于使用的場景和錯(cuò)誤處理 來說,調(diào)用另外一臺計(jì)算機(jī)上不同虛擬機(jī)中的對象的方法其處理有所不同。

與不使用Spring方式的EJB客戶端相比,Spring的EJB客戶端有一個(gè)額外的 好處。通常如果客戶端代碼隨意在本地EJB和遠(yuǎn)程EJB的調(diào)用之間來回切換,就有 一個(gè)問題。這是因?yàn)檫h(yuǎn)程接口的方法需要聲明其會(huì)拋出RemoteException?,然后客戶端代碼必須處理這種異常,但是本地接口的方法卻不需要這樣。 如果要把針對本地EJB的代碼改為訪問遠(yuǎn)程EJB,就需要修改客戶端代碼,增加 對RemoteException的處理,反之就需要去掉這樣的 異常處理。使用Spring 的遠(yuǎn)程EJB代理,我們就不再需要在業(yè)務(wù)方法接口和EJB的 代碼實(shí)現(xiàn)中聲明會(huì)拋出RemoteException,而是定義一個(gè) 相似的遠(yuǎn)程接口,唯一不同就是它拋出的是RemoteAccessException, 然后交給代理對象去動(dòng)態(tài)的協(xié)調(diào)這兩個(gè)接口。也就是說,客戶端代碼不再需要與?RemoteException這個(gè)顯式(checked)異常打交道,實(shí)際運(yùn)行中 所有拋出的異常RemoteException都會(huì)被捕獲并轉(zhuǎn)換成一個(gè) 隱式(non-checked)的RemoteAccessException,它是?RuntimeException的一個(gè)子類。這樣目標(biāo)服務(wù)端就可以 在本地EJB或遠(yuǎn)程EJB(甚至POJO)之間隨意地切換,客戶端不再需要關(guān)心甚至 根本不會(huì)覺察到這種切換。當(dāng)然,這些都是可選的,我們并不阻止在業(yè)務(wù)接口中聲明 異常RemoteExceptions。

15.2.?使用Spring提供的輔助類實(shí)現(xiàn)EJB組件

Spring也提供了一些輔助類來為EJB組件的實(shí)現(xiàn)提供便利。它們是為了倡導(dǎo)一些 好的實(shí)踐經(jīng)驗(yàn),比如把業(yè)務(wù)邏輯放在在EJB層之后的POJO中實(shí)現(xiàn),只把事務(wù)隔離和 遠(yuǎn)程調(diào)用這些職責(zé)留給EJB。

要實(shí)現(xiàn)一個(gè)無狀態(tài)或有狀態(tài)的Session Bean,或消息驅(qū)動(dòng)Bean,我們的實(shí)現(xiàn) 可以繼承分別繼承AbstractStatelessSessionBean,?AbstractStatefulSessionBean,和?AbstractMessageDrivenBean/AbstractJmsMessageDrivenBean

考慮這個(gè)例子:我們把無狀態(tài)Session Bean的實(shí)現(xiàn)委托給普通的Java服務(wù)對象。 業(yè)務(wù)接口的定義如下:

public interface MyComponent {public void myMethod(...);... }

這是簡單Java對象實(shí)現(xiàn)方式的類:

public class MyComponentImpl implements MyComponent {public String myMethod(...) {...}... }

最后是無狀態(tài)Session Bean自身:

public class MyComponentEJB implements extends AbstractStatelessSessionBeanimplements MyComponent {MyComponent _myComp;/*** Obtain our POJO service object from the BeanFactory/ApplicationContext* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()*/protected void onEjbCreate() throws CreateException {_myComp = (MyComponent) getBeanFactory().getBean(ServicesConstants.CONTEXT_MYCOMP_ID);}// for business method, delegate to POJO service impl.public String myMethod(...) {return _myComp.myMethod(...);}... }

Spring為支持EJB而提供的這些基類默認(rèn)情況下會(huì)創(chuàng)建并載入一個(gè)BeanFactory (這個(gè)例子里,它是ApplicationContext的子類),作為其生命周期的一部分, 供EJB使用(比如像上面的代碼那樣用來獲取POJO服務(wù)對象)。載入的工作是通過 一個(gè)策略對象完成的,它是BeanFactoryLocator的子類。 默認(rèn)情況下,實(shí)際使用的BeanFactoryLocator的實(shí)現(xiàn)類是?ContextJndiBeanFactoryLocator,它根據(jù)一個(gè)JNDI環(huán)境變量 來創(chuàng)建一個(gè)ApplicationContext對象(這里是EJB類,路徑是?java:comp/env/ejb/BeanFactoryPath)。如果需要改變 BeanFactory或ApplicationContext的載入策略,我們可以在子類中重定義了的?setSessionContext()方法或具體EJB子類的構(gòu)造函數(shù)中調(diào)用?setBeanFactoryLocator()方法來改變默認(rèn)使用的?BeanFactoryLocator實(shí)現(xiàn)類。具體細(xì)節(jié)請參考JavaDoc。

如JavaDoc中所述,有狀態(tài)Session Bean在其生命周期中可能會(huì)被鈍化并重新激活, 如果是不可序列化的BeanFactory或ApplicationContext,由于它們不會(huì)被EJB容器保存, 所以還需要手動(dòng)在ejbPassivate和ejbActivate?這兩個(gè)方法中分別調(diào)用unloadBeanFactory()和loadBeanFactory, 才能在鈍化或激活的時(shí)候卸載或載入。

有些情況下,要載入ApplicationContext以使用EJB組件,?ContextJndiBeanFactoryLocator的默認(rèn)實(shí)現(xiàn)基本上足夠了, 不過,當(dāng)ApplicationContext需要載入多個(gè)bean,或這些bean初始化所需的時(shí)間或內(nèi)存 很多的時(shí)候(例如Hibernate的SessionFactory的初始化),就有可能出問題,因?yàn)?每個(gè)EJB組件都有自己的副本。這種情況下,用戶會(huì)想重載?ContextJndiBeanFactoryLocator的默認(rèn)實(shí)現(xiàn),并使用其它?BeanFactoryLocator的變體,例如ContextSingleton?或者BeanFactoryLocator,他們可以載入并共享一個(gè) BeanFactory或ApplicationContext來為多個(gè)EJB組件或其它客戶端所公用。這樣做 相當(dāng)簡單,只需要給EJB添加類似于如下的代碼:

/*** Override default BeanFactoryLocator implementation* * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)*/public void setSessionContext(SessionContext sessionContext) {super.setSessionContext(sessionContext);setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);}

請參考相應(yīng)的JavaDoc來獲取關(guān)于BeanFactoryLocator,?ContextSingleton以及BeanFactoryLocator?的用法的詳細(xì)信息。


from:?http://docs.huihoo.com/spring/zh-cn/ejb.html

總結(jié)

以上是生活随笔為你收集整理的Spring - Java/J2EE Application Framework 应用框架 第 15 章 EJB的存取和实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。