首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Spring訪問與實現EJB:從服務定位器到代理模式的演進

     編輯:Java 程式設計入門

背景:為什麼在Spring中集成EJB?

Spring常被視為EJB輕量級替代品,但現實場景中:

  • 企業遺留系統大量使用EJB(特別是無狀態Session Bean/SLSB)
  • 需漸進式遷移:先用Spring管理業務邏輯,再逐步替換EJB實現
  • 需支持多種服務實現無縫切換:本地EJB、遠程EJB、POJO,客戶端代碼零修改

Spring通過代理模式封裝EJB訪問細節,消除樣板代碼(JNDI查找、Home創建、異常處理),實現依賴注入式EJB消費。

核心痛點:傳統EJB客戶端代碼的弊端

// 傳統方式:充斥樣板代碼
Context ctx = new InitialContext();
Object ref = ctx.lookup("ejb/MyBean");
MyHome home = (MyHome) PortableRemoteObject.narrow(ref, MyHome.class);
MyRemote bean = home.create(); // 拋出CreateException、RemoteException
bean.doBusiness(); // 業務調用

引入Service Locator和Business Delegate模式雖緩解,但引入新問題:難以單元測試、仍耦合EJB API、產生大量委托方法樣板代碼。

Spring方案:代理工廠Bean封裝EJB訪問

訪問本地SLSB:LocalStatelessSessionProxyFactoryBean

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

<bean id="myController" class="com.mycom.MyController">
    <property name="myComponent" ref="myComponent" /> <!-- 注入代理 -->
</bean>

關鍵機制:

  • 代理實現業務接口MyComponent,控制器僅依賴接口
  • 啟動時緩存Home對象,僅一次JNDI查找
  • 每次調用代理→home.create()→業務方法→移除實例(SLSB無狀態)
  • AOP攔截器LocalSlsbInvokerInterceptor處理創建/調用/異常轉換

訪問遠程SLSB:SimpleRemoteStatelessSessionProxyFactoryBean

配置類似,但關鍵差異在異常處理:

  • 遠程接口方法拋RemoteException(受檢異常),客戶端被迫捕獲
  • Spring代理定義業務接口不拋RemoteException,運行時捕獲並包裝為RemoteAccessException(繼承RuntimeException,非受檢)
  • 結果:客戶端代碼無需處理RemoteException,可在本地/遠程/POJO實現間透明切換

Spring輔助類實現EJB:將業務邏輯下沉到POJO

提倡「EJB只做容器服務(事務/安全/遠程),業務邏輯放POJO」:

// 業務接口
public interface MyComponent { void myMethod(); }

// POJO實現(純Java,無EJB依賴)
public class MyComponentImpl implements MyComponent {
    public void myMethod() { /* 核心業務邏輯 */ }
}

// 無狀態Session Bean:薄包裝層
public class MyComponentEJB extends AbstractStatelessSessionBean implements MyComponent {
    private MyComponent myComp;
    
    protected void onEjbCreate() throws CreateException {
        // 從BeanFactory獲取POJO實例
        myComp = (MyComponent) getBeanFactory().getBean("myComponent");
    }
    
    public void myMethod() { myComp.myMethod(); } // 委托調用
}

基類體系

BeanFactory定位策略:ContextJndiBeanFactoryLocator

  • 默認:JNDI環境變量java:comp/env/ejb/BeanFactoryPath指向ApplicationContext配置文件
  • 每個EJB實例擁有獨立BeanFactory副本 → 內存浪費(特別是Hibernate SessionFactory等重資源)
  • 優化:使用ContextSingletonBeanFactoryLocator共享單例ApplicationContext
public void setSessionContext(SessionContext ctx) {
    super.setSessionContext(ctx);
    setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
    setBeanFactoryLocatorKey("mainContext"); // 指向共享上下文鍵
}

關鍵配置陷阱:Lazy-init避免啟動競態

若Bean容器預實例化單例(如ClassPathXmlApplicationContext),且EJB容器尚未綁定目標EJB,JNDI查找失敗。解決:代理工廠Bean設置lazy-init="true",首次使用時才創建並查找。

總結:Spring + EJB 集成最佳實踐

  1. 定義業務接口(POJO接口),EJB本地/遠程接口擴展它
  2. 業務邏輯實現為POJO,由Spring管理生命周期/依賴
  3. EJB作為薄適配層,繼承Spring基類,onEjbCreate注入POJO,委托調用
  4. 客戶端注入代理(Local/SimpleRemoteStatelessSessionProxyFactoryBean),依賴業務接口
  5. 共享ApplicationContext(ContextSingletonBeanFactoryLocator),避免重複初始化重資源
  6. 異常透明化:遠程調用自動轉換RemoteException為非受檢異常

這種模式實現了「容器服務與業務邏輯分離、實現細節與客戶端解耦、遷移路徑平滑可控」,是遺留系統現代化改造的經典範式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
Bean類型Spring基類關鍵模板方法
無狀態Session BeanAbstractStatelessSessionBeanonEjbCreate()、setSessionContext()
有狀態Session BeanAbstractStatefulSessionBeanejbPassivate()/ejbActivate()管理BeanFactory序列化
消息驅動BeanAbstractMessageDrivenBean / AbstractJmsMessageDrivenBeanonEjbCreate()、setMessageDrivenContext()