Spring 常被視為 EJB 的輕量級替代方案,但實際上 Spring 並非排斥 EJB,反而提供了極致優雅的整合機制。本章深入解析 Spring 如何簡化 EJB 存取與實作,實現本地/遠端 EJB 與 POJO 服務的無縫切換。
傳統客戶端需手寫 JNDI 查找、Home 介面 create() 呼叫、異常處理,程式碼散佈業務邏輯。服務定位器與業務委派模式雖有改善,卻引入測試困難、耦合 EJB API、大量樣板代碼等新問題。
Spring 採用 AOP 代理,在 ApplicationContext 宣告式配置即可完成 EJB 存取:
<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>
核心優勢:
MyComponent,零 EJB API 洩漏。遠端介面拋出 RemoteException 導致客戶端代碼難以在本地/遠端間切換。Spring 的 SimpleRemoteStatelessSessionProxyFactoryBean 方案:
RemoteAccessException(RuntimeException 子類)。RemoteException 並轉換為 RemoteAccessException。Spring 倡導「EJB 薄殼,業務邏輯下沉 POJO」:
public class MyComponentEJB extends AbstractStatelessSessionBean implements MyComponent {
private MyComponent myComp; // POJO 服務實作
protected void onEjbCreate() {
myComp = (MyComponent) getBeanFactory().getBean("myComponentId");
}
public String myMethod() {
return myComp.myMethod(); // 委派給 POJO
}
}
關鍵機制:
AbstractStatelessSessionBean 等基類整合 BeanFactoryLocator,預設用 ContextJndiBeanFactoryLocator 從 JNDI java:comp/env/ejb/BeanFactoryPath 載入 ApplicationContext。ejbPassivate/ejbActivate 手動卸載/載入 BeanFactory(非序列化情況)。ApplicationContext 時,改用 ContextSingletonBeanFactoryLocator 避免重複初始化昂貴資源(如 Hibernate SessionFactory)。Spring 以宣告式代理消除 EJB 存取樣板代碼,以輔助類推動業務邏輯 POJO 化,讓開發者專注核心業務,同時保留 EJB 容器級服務(事務、安全、遠端調用)的彈性選擇權。