Eclipse 的組件模型建立在插件與擴展點之上,但傳統 plugin.xml 靜態註冊方式導致插件間形成硬性依賴。本文透過一個同義詞註冊服務的實戰範例,示範如何結合 OSGi 服務監聽器與 Eclipse 3.2 引入的動態擴展貢獻 API (IExtensionRegistry.addContribution()),實現插件的完全解耦與動態組裝。
假設核心插件 com.company.SynonymRegistry 定義擴展點「synonym」,允許第三方貢獻詞彙映射。中介插件需讀取 XML 配置並在核心服務可用時動態註冊,且不得因核心插件缺失而導致啟動失敗。
中介插件在 start(BundleContext context) 中註冊服務監聽器:
context.addServiceListener(this, "(objectClass=com.company.SynonymRegistry)");
過濾器確保僅接收目標服務的註冊/註銷事件。若服務尚未啟動,中介插件緩存 XML 數據;服務上線時自動觸發註冊邏輯。
Eclipse 3.2 開放 IExtensionRegistry.addContribution(InputStream, Bundle, ...),允許運行時注入擴展 XML。核心代碼:
IExtensionRegistry registry = RegistryFactory.getRegistry();
ByteArrayInputStream is = new ByteArrayInputStream(xmlContent.getBytes());
Object token = null; // Eclipse 3.2+ 需啟動參數 -Declipse.registry.nulltoken=true
registry.addContribution(is, bundle, null, null, token);
XML 結構與靜態 plugin.xml 完全一致:
<plugin>
<extension point="com.company.synonymregistry" id="myExtension">
<synonyms word="mediator" synonym="broker"/>
</extension>
</plugin>
addContribution() 為非同步操作,擴展不會立即生效。若業務邏輯需即時使用,必須實作同步等待:
RegistryChangeListener 的 JobisRegistered 事件集合建議採用惰性初始化設計,避免阻塞啟動流程。
完整範例代碼展示了從 XML 解析、服務監聽、動態註冊到同步等待的完整鏈路,可直接應用於類似「插件化功能熱插拔」的業務場景。