本文介紹了一個采用 XML 的插件示例,以便為定義好的擴展點注冊擴展。通過使插件能夠感知 Extention Registry 并提供 OSGi 服務,我們可以完成這一完整的組件退耦操作。
插件、擴展點、OSGi
如您所知,Eclipse 的組件架構是基于插件 的 -- 這意味著將一組代碼組件化為單一的組件,然后利用 Eclipse 框架注冊為其組件之一,其他組件可以綁定該組件或調用該組件。擴展點 是插件允許其他插件向公開擴展點的插件提供附加功能的方法?,F在利用所有這些插件并將其包裝到受控的運行時,插件可在其中動態進出,并且您可以獲得 OSGi(基本上來說)。
示例插件
讓我們從公開擴展點的基本插件開始,這樣可以為同義詞服務注冊新的字符串映射。此項服務允許其他服務注冊一個詞并將其映射到另一個詞(同義詞)?;緮U展包含非常簡單的元素:一個詞,當然還有一個新的同義詞。此插件擴展點的基本結構如表 1 所示。
插件名稱 | com.company.SynonymRegistry |
---|---|
擴展點 | 同義詞 |
元素 | 詞 -- 您想要為其添加同義詞的詞 同義詞 -- 您想要注冊的同義詞 |
我們還要將插件注冊為 OSGi 服務。這意味著它只在顯式執行此操作時被加載,并將可供其他客戶聲明性地使用。為了使用該服務,其他客戶只需了解 Interface 和 OSGi 類名稱。在我們的示例中,我們不會真正調用該服務,因為擴展點是假設的。我們將使用 OSGi API 以告知我們此項服務出入的時間,所以我們可以正確地注冊擴展點。
現在這只是一個示例,并且使用針對此概念的擴展點可能不是最好的方法。我們用此基本示例要達到的目的是如何動態注冊新的擴展,同時說明使用 OSGi API 的插件生命周期事件。
Mediator 插件
下一個插件是第三方插件,該插件了解已知的服務和擴展點,但不想綁定到此插件,因為后面它將依靠該插件進行運行時解析。這意味著該插件可以駐留在所引用的插件 (com.company.SynonymRegistry) 可能不存在的機器上。因為我們現在生活在 OSGi 和動態運行時世界,所以我們想確保插件在不引起運行時故障或錯誤的情況下運行。我們的 mediator 插件將接受同義詞的 XML 文件,并且通過使用提供的擴展點用 SynonymRegistry 插件注冊每個同義詞。
|
Mediator 插件在其 start()
方法中做的第一件事是用 OSGi 服務注冊為一個服務初始化偵聽器。我們要在傳入 start()
方法的 BundleContext 對象上調用 OSGi 服務方法 addServiceListener()
。以下代碼展示了一個通過傳入代碼和我們感興趣的服務 ID 調用此 API 的示例。
|
通過提供過濾器,可以告知 OSGi 服務注冊中心只需通知您指定服務中的狀態更改。在本例中,過濾器只是 SynonymRegistry 類的類名稱。
您可能會尋根究底。答案就在啟動序列中。在 OSGi 領域,我們不是總知道另一服務可用的時間,因此我們需要對此進行說明。通過注冊為服務偵聽器,我們可得知服務開始和停止的時間。如果服務不可用,則允許我們緩存同義詞。當服務確實可用時,我們會得到通知并注冊擴展。
注冊新擴展
下面我們將講述本文的核心內容?,F在我們有了想為其提供動態擴展的數據 (Synonyms.xml) 和已知的擴展點 (com.company.SynonymRegistry. Synonym)。由于我們不知道何時初始化插件,也不知道是否初始化 Synonym 插件,所以我們只要在加載插件時嘗試注冊 XML 文件中的條目即可。請記?。哼@是一個展示概念的示例,不應在生產代碼中這樣實施。通常,我們盡可能多地以惰性方式(延遲或在需要時)執行初始化。
Eclipse V3.2 中的新特性是能夠在運行時提供擴展。例如,客戶可以編寫一個包含某個視圖的應用程序,該視圖可以在單擊按鈕時創建一個透視圖。透視圖被添加到擴展注冊表,然后在可用透視圖的列表中顯示。此功能的重要好處之一是它可以減輕插件之間的“硬”依賴性。插件 A 可供在插件 B 中定義的平臺使用,無需依賴插件 B。而且,通過將此功能與 OSGi 框架結合,插件可以檢查服務的存在性,如果存在,可從服務中定義的擴展點創建擴展。這在使用面向服務架構的原則同時,促進了真正動態的環境。
Eclipse V3.2 中新公開的是 addContribution()
方法,該方法在 IExtensionRegistry
接口中定義。清單 2 中的代碼展示了可以通過 addContribution()
API 添加擴展的方法。addContribution()
方法旨在采用普通 XML 作為第一個參數中的 InputStream
。
|
編寫本文的時候 -- 意味著這是一個更改 Eclipse 未來版本的好機會 -- 允許公眾訪問注冊表的用戶標記可以使用此內部 Eclipse 調用獲得。下面的代碼展示了內部 API (getTemporaryUserToken()
) 的使用。
|
但是,在里程碑式的下一版本 Eclipse V3.2 版本中,此標記不能公開訪問。為了支持應用程序中的動態擴展,啟動程序必須提供以下針對虛擬機的設置:
|
此定義現在允許我們將 null
用作 addContribution()
API 中的 User Token?,F在,我們的代碼看上去類似如下。有關此問題中的 Bugzilla 對話,請參見 Bugzilla bug 清單。
|
上面顯示的緩沖區變量表示實際的 XML 塊。此 XML 是我們可以在 plugin.xml 文件內看到的精確副本?;氐轿覀兊?SynonymRegistry 示例,此擴展的 XML 將類似清單 4。
|
客戶可以考慮創建一個接受以下參數的包裝工廠類,如擴展點 ID、擴展 ID、元素名稱(本例中是同義詞)、實際屬性和資源包 ID。該包裝類將參數格式化為類似上面代碼的 XML 字符串。然后將此 XML 字符串讀入將被傳入到 IExtensionRegistry
接口的 addContribution()
方法的 ByteArrayInputStream
中。只有此方法的其他必需參數是用戶標記和資源包 ID。值得注意的一點是,資源包 ID 應是做出該貢獻的資源包的 ID,不是在其中定義擴展點的資源包的 ID。
警告和提示
在 M5(于 2006 年 2 月 17 日構建的 Eclipse)中引入的一個特性是,對 addContributions()
的調用是異步調用。這意味著該擴展不可立即使用,因為 Eclipse 啟動了一項執行實際注冊的作業。簡單地說,您必須開始自己的作業并與之同步,以獲得任何類型的同步行為。
為了使此項任務更容易,下面給出了三條提示:
RegistryChangeListener
的新作業。 RegistryListener
回調的 isRegistered
集合。 當然,現在我們必須將調用代碼與生成的作業結合起來,以獲得同步調用。這只有在代碼要求立即使用擴展時才得到保證。希望您的代碼設計為惰性,這樣初始化就變得不重要。
結束語
動態擴展的使用可以通過編程方式創建。通過使用 OSGi 框架偵聽服務何時可用(加載或卸載),動態擴展增強了退耦功能。一起使用這些技術將允許聲明性的貢獻和組件之間 100% 退耦。
原文轉自:http://www.anti-gravitydesign.com