?
このドキュメントでは、 php中國(guó)語(yǔ)ネットマニュアル リリース
Spring也提供了一些輔助類來(lái)為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è)無(wú)狀態(tài)或有狀態(tài)的Session Bean,或消息驅(qū)動(dòng)Bean,你只需要從AbstractStatelessSessionBean
、AbstractStatefulSessionBean
和AbstractMessageDrivenBean
/AbstractJmsMessageDrivenBean
分別繼承你的實(shí)現(xiàn)類。
考慮這個(gè)無(wú)狀態(tài)Session bean的例子:實(shí)際上我們把無(wú)狀態(tài)Session Bean的實(shí)現(xiàn)委托給一個(gè)普通的Java服務(wù)對(duì)象。業(yè)務(wù)接口的定義如下:
public interface MyComponent { public void myMethod(...); ... }
這是簡(jiǎn)單Java對(duì)象的實(shí)現(xiàn):
public class MyComponentImpl implements MyComponent { public String myMethod(...) { ... } ... }
最后是無(wú)狀態(tài)Session Bean自身:
public class MyFacadeEJB extends AbstractStatelessSessionBean implements MyFacadeLocal { private 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 myFacadeMethod(...) { return myComp.myMethod(...); } ... }
缺省情況下,Spring EJB支持類的基類在其生命周期中將創(chuàng)建并加載一個(gè)Spring IoC容器供EJB使用(比如像前面獲得POJO服務(wù)對(duì)象的代碼)。加載的工作是通過(guò)一個(gè)策略對(duì)象完成的,它是BeanFactoryLocator
的子類。
默認(rèn)情況下,實(shí)際使用的BeanFactoryLocator
的實(shí)現(xiàn)類是ContextJndiBeanFactoryLocator
,它根據(jù)一個(gè)被指定為JNDI環(huán)境變量的資源位置來(lái)創(chuàng)建一個(gè)ApplicationContext對(duì)象(對(duì)于EJB類,路徑是
java:comp/env/ejb/BeanFactoryPath
)。如果需要改變BeanFactory或ApplicationContext的載入策略,我們可以在
setSessionContext()
方法調(diào)用或在具體EJB子類的構(gòu)造函數(shù)中調(diào)用setBeanFactoryLocator()
方法來(lái)覆蓋默認(rèn)使用的
BeanFactoryLocator
實(shí)現(xiàn)類。具體細(xì)節(jié)請(qǐng)參考JavaDoc。
如JavaDoc中所述,有狀態(tài)Session Bean在其生命周期中將會(huì)被鈍化并重新激活,由于(一般情況下)使用了一個(gè)不可串行化的容器實(shí)例,不可以被EJB容器保存,
所以還需要手動(dòng)在ejbPassivate
和ejbActivate
這兩個(gè)方法中分別調(diào)用unloadBeanFactory()
和loadBeanFactory
,
才能在鈍化或激活的時(shí)候卸載或載入。
有些情況下,要載入ApplicationContext以使用EJB組件,ContextJndiBeanFactoryLocator
的默認(rèn)實(shí)現(xiàn)基本上足夠了,
不過(guò),當(dāng)ApplicationContext
需要載入多個(gè)bean,或這些bean初始化所需的時(shí)間或內(nèi)存
很多的時(shí)候(例如Hibernate的SessionFactory
的初始化),就有可能出問題,因?yàn)?每個(gè)EJB組件都有自己的副本。這種情況下,用戶會(huì)想重載ContextJndiBeanFactoryLocator
的默認(rèn)實(shí)現(xiàn),并使用其它
BeanFactoryLocator
的變體,例如ContextSingletonBeanFactoryLocator
,他們可以載入并在多個(gè)EJB或者其客戶端間共享一個(gè)容器。這樣做相當(dāng)簡(jiǎn)單,只需要給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); }
然后需要?jiǎng)?chuàng)建一個(gè)名為beanRefContext.xml
的bean定義文件。這個(gè)文件定義了EJB中所有可能用到的bean工廠(通常以應(yīng)用上下文的形式)。許多情況下,這個(gè)文件只包括一個(gè)bean的定義,如下所示(文件businessApplicationContext.xml
包括了所有業(yè)務(wù)服務(wù)POJO的bean定義):
<beans> <bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg value="businessApplicationContext.xml" /> </bean> </beans>
上例中,常量ServicesConstants.PRIMARY_CONTEXT_ID
定義如下:
public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";
BeanFactoryLocator
和類ContextSingletonBeanFactoryLocator
的更多使用信息請(qǐng)分別查看他們各自的Javadoc文檔。
對(duì)EJB3 Session bean和Message-Driven Bean來(lái)說(shuō), Spring在EJB組件類
org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor
中提供了實(shí)用的攔截器來(lái)解析Spring2.5的注解@Autowired
。
這個(gè)攔截器的使用有兩種方式,可以在EJB組件類里使用@Interceptors
注解,也可以在EJB部署描述文件中使用XML元素interceptor-binding
。
@Stateless @Interceptors(SpringBeanAutowiringInterceptor.class) public class MyFacadeEJB implements MyFacadeLocal { // automatically injected with a matching Spring bean @Autowired private MyComponent myComp; // for business method, delegate to POJO service impl. public String myFacadeMethod(...) { return myComp.myMethod(...); } ... }
SpringBeanAutowiringInterceptor
默認(rèn)情況下是從ContextSingletonBeanFactoryLocator
獲得目標(biāo)bean的,后者定義在beanRefContext.xml
文件中。通常情況下,最好使用單獨(dú)的上下文定義,并且根據(jù)類型而不是名稱來(lái)獲得。然而,如果你需要在多個(gè)上下文定義中切換,那么就需要一個(gè)特定的定位鍵。這個(gè)定位鍵(例如定義在beanRefContext.xml
中的上下文名稱)可以通過(guò)以下兩種方式來(lái)明確的指定。一種方式是在定制的SpringBeanAutowiringInterceptor
子類中重寫getBeanFactoryLocatorKey
方法。
另一種方式是重寫SpringBeanAutowiringInterceptor
的
getBeanFactory
方法,例如從定制支持類中獲得一個(gè)共享的ApplicationContext
。