Eclipse RCP (Rich Client Platform) 架構下,每個外掛擁有獨立 ClassLoader,導致 Spring 無法直接定位 applicationContext.xml,且 BeanFactory 管理缺乏統一入口。本文介紹 **EclipseSpring** 專案 (SourceForge) 提供的整合方案:透過擴展點註冊 BeanFactoryContributor、自訂 SpringExtensionFactory 實現類載入切換與 BeanFactory 集中管理,並以 View 為例示範完整整合流程。
| 問題 | 原因 | 影響 |
|---|---|---|
| 找不到配置檔 | 各外掛獨立 ClassLoader,預設 ClassLoader 不可見其他外掛資源 | ClassPathXmlApplicationContext 拋出 FileNotFoundException |
| BeanFactory 管理分散 | 每個外掛若自建 BeanFactory,重複初始化、無法跨外掛注入、生命週期難協調 | 記憶體浪費、依賴解析失敗、啟動順序混亂 |
定義於 `plugin.xml`,允許各外掛貢獻 Bean 定義:
<extension point="net.sourceforge.eclipsespring.beanFactoryContributors">
<beanFactoryContributor
class="com.example.spring.BeanFactoryContributor"
id="example"/>
</extension>
BeanFactoryContributor 介面:
public interface BeanFactoryContributor {
String[] getConfigLocations(); // 返回該外掛的 Spring 配置檔路徑 (相對於外掛根目錄)
void postProcessBeanFactory(ConfigurableListableBeanFactory bf); // 可選:註冊後置處理器等
}
Eclipse 擴展點工廠機制,負責在正確 ClassLoader 下建立 Spring Bean:
public class SpringExtensionFactory extends AbstractExtensionFactory {
@Override
public Object create() throws CoreException {
// 1. 解析配置參數:bundleId/viewId 等
// 2. 取得對應外掛的 Bundle
// 3. 使用 Bundle 的 ClassLoader 建立/取得共享 ApplicationContext
// 4. 從 Context 獲取指定 Bean (view 實例)
return bean;
}
}
在 `plugin.xml` 宣告 View 時指定工廠:
<extension point="org.eclipse.ui.views">
<view
name="Spring View"
class="net.sourceforge.eclipsespring.SpringExtensionFactory:com.example.UserNameView"
id="example.userNameView"/>
</extension>
格式:`FactoryClass:parameter`,參數傳遞給工廠識別目標 Bean。
ApplicationContext (父子上下文可選)。WorkbenchAdvisor.postStartup() 初始化,preShutdown() 關閉。<beans>
<bean id="userNameView" class="com.example.UserNameView">
<property name="greeting" value="Hello from Spring!"/>
</bean>
</beans>
public class BeanFactoryContributor implements net.sourceforge.eclipsespring.BeanFactoryContributor {
@Override public String[] getConfigLocations() { return new String[]{"spring/context.xml"}; }
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {}
}
| 主題 | 解決方案 |
|---|---|
| 跨外掛 Bean 注入 | 父子 ApplicationContext:平台層父 Context 載入核心服務,外掛子 Context 繼承並可覆蓋/新增 Bean。 |
| OSGi 服務動態發現 | 整合 Spring Dynamic Modules (Spring DM) / Blueprint,將 OSGi 服務導出為 Spring Bean,反之亦然。 |
| 非 UI 執行緒存取 Context | 實作 ApplicationContextAware 或注入 ApplicationContext,注意執行緒安全。 |
| 測試策略 | 單元測試直接載入 Spring 配置;整合測試使用 EclipseTestRunner 啟動 OSGi 框架。 |
Eclipse 4 (e4) 引入標準化依賴注入機制 (@Inject, IEclipseContext) 取代傳統擴展點工廠,原生支援:
遷移建議:新 RCP 專案優先採用 e4 DI;存量 Spring 整合專案可平滑共存 (e4 相容層支援舊擴展點)。
EclipseSpring 透過 BeanFactoryContributor 擴展點收斂配置、SpringExtensionFactory 解決類載入隔離、共享 ApplicationContext 統一 Bean 管理,成功將 Spring IOC 引入 Eclipse RCP。理解其核心機制——**擴展點作為模組邊界契約、Bundle ClassLoader 作為資源可見性邊界、工廠模式解耦實例化邏輯**——對掌握模組化架構下依賴注入整合具有普遍指導意義。