如果你選擇使用EJB,Spring能在EJB實(shí)現(xiàn)和客戶端訪問(wèn)EJB兩方面都提供很大的好處。
對(duì)業(yè)務(wù)邏輯進(jìn)行重構(gòu),把它從EJB facades中取出到POJO已經(jīng)得到了廣泛的認(rèn)同。(不講別的,這使得業(yè)務(wù)邏輯更容易單元測(cè)試,因?yàn)镋JB嚴(yán)重依賴于容器而難于分離測(cè)試。)Spring為session bean和message driver bean提供了方便的超類,使得通過(guò)自動(dòng)載入基于包含在EJB Jar文件中的XML文檔BeanFactory讓這變得很容易。
這意味著stateless session EJB可以這么獲得和使用所需對(duì)象:
代碼: |
import org.springframework.ejb.support.AbstractStatelessSessionBean; public class MyEJB extends AbstractStatelessSessionBean implements MyBusinessInterface { private MyPOJO myPOJO; protected void onEjbCreate() { this.myPOJO = getBeanFactory().getBean("myPOJO"); } public void myBusinessMethod() { this.myPOJO.invokeMethod(); } } |
假定MyPOJO是一個(gè)接口,它的實(shí)現(xiàn)類——以及任何它需要的配置,注入基本的屬性和更多的合作者——在XML bean factory 定義中隱藏。
我們通過(guò)在ejb-jar.xmldeployment descriptor中名為ejb/BeanFactoryPath的環(huán)境變量定義告訴Spring去哪兒裝載XML文檔。如下:
代碼: |
<session> <ejb-name>myComponent</ejb-name> <local-home>com.test.ejb.myEjbBeanLocalHome</local-home> <local>com.mycom.MyComponentLocal</local> <ejb-class>com.mycom.MyComponentEJB</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <env-entry> <env-entry-name>ejb/BeanFactoryPath</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>/myComponent-ejb-beans.xml</env-entry-value></env-entry> </env-entry> </session> |
myComponent-ejb-beans.xml 文件將會(huì)從classpath裝載:在本例中,是EJB Jar文件的根目錄。每個(gè)EJB都能指定自己的XML文檔,因而這個(gè)機(jī)制能在每個(gè)EJB Jar文件中使用多次。
Spring 的超類實(shí)現(xiàn)了EJB中諸如setSessionContext()和ejbCreate()的生命周期管理的方法,讓應(yīng)用程序開發(fā)者只需選擇是否實(shí)現(xiàn)Spring的onEjbCreate()方法。
使用EJB
Spring還讓實(shí)現(xiàn)EJB變得更加容易。許多EJB程序使用Service Locator和Business Delegate模式。這些比在客戶代碼中遍布JNDI查找強(qiáng)多了,但是它們常見的實(shí)現(xiàn)方式有顯著的缺點(diǎn),例如:
基于這些和其他原因,傳統(tǒng)的EJB訪問(wèn),如在Sun Adventure Builder和OTN J2EE Virtual Shopping Mall中展示的那樣,會(huì)降低生產(chǎn)率并且?guī)?lái)顯著的復(fù)雜度。
Spring通過(guò)引入codeless business delegate前進(jìn)了一步。有了Spring,你不再需要再編寫另一個(gè)Service Locator,另一個(gè)JNDI查找,或者在硬編碼的Business Delegate中重復(fù)代碼,除非你肯定這增加了價(jià)值。
例如,假定我們有使用local EJB的web controller。我們將遵循最佳實(shí)踐,使用EJB Business Methods Interface模式,EJB的local interface extend非EJB專有的業(yè)務(wù)方法接口。(這么做的主要的一個(gè)原因是確保在本地接口和bean實(shí)現(xiàn)類中方法簽名的自動(dòng)同步。)讓我們調(diào)用這個(gè)業(yè)務(wù)方法接口MyComponent。當(dāng)然我們還需要實(shí)現(xiàn)local home接口并且提供實(shí)現(xiàn)SessionBean和MyComponent業(yè)務(wù)方法的bean的實(shí)現(xiàn)類。
用了Spring EJB 訪問(wèn),我們把我們的web層controller和EJB實(shí)現(xiàn)掛接上所需要進(jìn)行的Java編碼僅僅是在我們的controller中暴露一個(gè)類型MyComponent的setter方法。這將如下保存作為實(shí)例變量的引用:
我們隨后在任何業(yè)務(wù)方法中使用這個(gè)實(shí)例變量。
Spring自動(dòng)完稱剩下的工作,通過(guò)像這樣的XML bean定義。LocalStatelessSessionProxyFactoryBean是一個(gè)可以用于任何EJB的通用factory bean。它創(chuàng)建的對(duì)象能夠自動(dòng)被Spring轉(zhuǎn)型為MyComponent類型。
在幕后有許多魔法般的事情發(fā)生,Spring AOP framework的殷勤,雖然不強(qiáng)迫你使用AOP的概念享受這些結(jié)果。“myComponent”bean定義為EJB創(chuàng)建一個(gè)代理,它實(shí)現(xiàn)了業(yè)務(wù)方法的接口。EJB local home在啟動(dòng)的時(shí)候被緩存,因而只需要一次JNDI查找。每次EJB被調(diào)用的時(shí)候,代理調(diào)用local EJB中的create()方法并且調(diào)用EJB中對(duì)應(yīng)的業(yè)務(wù)方法。
myController bean定義為這個(gè)代理設(shè)置controller類的myController屬性。
這個(gè)EJB訪問(wèn)機(jī)制極大簡(jiǎn)化了應(yīng)用程序的代碼:
在實(shí)際程序中的性能測(cè)試和經(jīng)驗(yàn)標(biāo)明這種方法(包括對(duì)目標(biāo)EJB的反射調(diào)用)的性能影響是很小的,在典型的應(yīng)用中檢測(cè)不出。記住無(wú)論如何我們都不希望使用fine-grained的EJB調(diào)用,因?yàn)闀?huì)有有關(guān)應(yīng)用服務(wù)器上的EJB的底層架構(gòu)方面的代價(jià)。
我們可以把相同方法應(yīng)用于遠(yuǎn)程EJB,通過(guò)類似org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean的方法。然而我們無(wú)法隱藏遠(yuǎn)程EJB的業(yè)務(wù)方法接口中的RemoteException。
Spring還讓實(shí)現(xiàn)EJB變得更加容易。許多EJB程序使用Service Locator和Business Delegate模式。這些比在客戶代碼中遍布JNDI查找強(qiáng)多了,但是它們常見的實(shí)現(xiàn)方式有顯著的缺點(diǎn),例如:
使用EJB的典型代碼依賴Service Locator或者Business Delegate singletons,使得測(cè)試難于進(jìn)行。
在Service Locator模式?jīng)]有使用Business Delegate的情況下,程序代碼還要在EJB home中調(diào)用create()方法,并且處理可能導(dǎo)致的異常。因而仍然綁定在EJB API身上,忍受著EJB 編程模型的復(fù)雜度。
實(shí)現(xiàn)Business Delegate模式通常導(dǎo)致顯著的代碼重復(fù),其中我們必須編寫大量?jī)H僅是調(diào)用EJB同等方法的方法。
基于這些和其他原因,傳統(tǒng)的EJB訪問(wèn),如在Sun Adventure Builder和OTN J2EE Virtual Shopping Mall中展示的那樣,會(huì)降低生產(chǎn)率并且?guī)?lái)顯著的復(fù)雜度。
Spring通過(guò)引入codeless business delegate前進(jìn)了一步。有了Spring,你不再需要再編寫另一個(gè)Service Locator,另一個(gè)JNDI查找,或者在硬編碼的Business Delegate中重復(fù)代碼,除非你肯定這增加了價(jià)值。
例如,假定我們有使用local EJB的web controller。我們將遵循最佳實(shí)踐,使用EJB Business Methods Interface模式,EJB的local interface extend非EJB專有的業(yè)務(wù)方法接口。(這么做的主要的一個(gè)原因是確保在本地接口和bean實(shí)現(xiàn)類中方法簽名的自動(dòng)同步。)讓我們調(diào)用這個(gè)業(yè)務(wù)方法接口MyComponent。當(dāng)然我們還需要實(shí)現(xiàn)local home接口并且提供實(shí)現(xiàn)SessionBean和MyComponent業(yè)務(wù)方法的bean的實(shí)現(xiàn)類。
用了Spring EJB 訪問(wèn),我們把我們的web層controller和EJB實(shí)現(xiàn)掛接上所需要進(jìn)行的Java編碼僅僅是在我們的controller中暴露一個(gè)類型MyComponent的setter方法。這將如下保存作為實(shí)例變量的引用:
代碼: |
private MyComponent myComponent; public void setMyComponent(MyComponent myComponent) { this.myComponent = myComponent; } |
我們隨后在任何業(yè)務(wù)方法中使用這個(gè)實(shí)例變量。
Spring自動(dòng)完稱剩下的工作,通過(guò)像這樣的XML bean定義。LocalStatelessSessionProxyFactoryBean是一個(gè)可以用于任何EJB的通用factory bean。它創(chuàng)建的對(duì)象能夠自動(dòng)被Spring轉(zhuǎn)型為MyComponent類型。
代碼: |
<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 framework的殷勤,雖然不強(qiáng)迫你使用AOP的概念享受這些結(jié)果。“myComponent”bean定義為EJB創(chuàng)建一個(gè)代理,它實(shí)現(xiàn)了業(yè)務(wù)方法的接口。EJB local home在啟動(dòng)的時(shí)候被緩存,因而只需要一次JNDI查找。每次EJB被調(diào)用的時(shí)候,代理調(diào)用local EJB中的create()方法并且調(diào)用EJB中對(duì)應(yīng)的業(yè)務(wù)方法。
myController bean定義為這個(gè)代理設(shè)置controller類的myController屬性。
這個(gè)EJB訪問(wèn)機(jī)制極大簡(jiǎn)化了應(yīng)用程序的代碼:
Web層的代碼不依賴于EJB的使用。如果你想要使用POJO,mock object或者其他test stub替代EJB引用,我們可以簡(jiǎn)單地改動(dòng)一下myComponent bean定義而不影響一行Java代碼
我們還不需要寫一行JNDI查找或者其他EJB plumbing code。
在實(shí)際程序中的性能測(cè)試和經(jīng)驗(yàn)標(biāo)明這種方法(包括對(duì)目標(biāo)EJB的反射調(diào)用)的性能影響是很小的,在典型的應(yīng)用中檢測(cè)不出。記住無(wú)論如何我們都不希望使用fine-grained的EJB調(diào)用,因?yàn)闀?huì)有有關(guān)應(yīng)用服務(wù)器上的EJB的底層架構(gòu)方面的代價(jià)。
我們可以把相同方法應(yīng)用于遠(yuǎn)程EJB,通過(guò)類似org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean的方法。然而我們無(wú)法隱藏遠(yuǎn)程EJB的業(yè)務(wù)方法接口中的RemoteException。