Eclipse(3.1) Plugin Framework(基於OSGI的Plugin Architecture)(轉載)

Eclipse(3.1) Plugin Framework(基於OSGI的Plugin Architecture)

概述
Eclipse中最出彩的部分莫過於它的Plugin Framework,可以說Eclipse在一定程度上使得Plugin機制得以流行,當然,Eclipse的優勢不僅僅在此,但正因爲採用了Plugin機制,Eclipse才得以被不斷的擴充,越來越強大。一直以來就想分析Eclipse的Plugin Framework,由於各種原因一直耽擱,剛好這個週末沒什麼事,下定決心對其進行了研究和分析,方法很原始,就是對Eclipse的啓動過程進行分析,基於的是Eclipse 3.1的版本,分析過程就不在這說了,主要是說說分析出來的心得。
架構上來講Eclipse基本採用的是Kernel+Core Plugins+Custom Plugins的結構體系,除了Kernel部分外均爲Plugin,所以可稱爲all are plugins,凡是Plugin的部分都是可被替換的。

OSGI
Eclipse 3.0後採用的是OSGI來作爲其Plugin Architecture實現的依據,鑑於此就得簡單提提OSGI了,主要從Plugin的角度來分析OSGI,OSGI概念中主要分爲了Bundle和Service,可以認爲Bundle是一個模塊的管理器,主要是通過BundleActivator管理模塊的生命週期,而Service則是這個模塊可暴露對外的服務對象,這裏體現了OSGI和傳統的Plugin Framework不同的一個地方,管理和靜態結構分開,在OSGI中通過在manifest.mf文件中增加一些內容來發布Bundle,在其中描述了Bundle的提供商、版本、唯一ID、classpath、暴露對外的包、所依賴的包;每個Bundle擁有自己的ClassLoader以及context,通過context可進行服務的註冊、卸載等,這些操作都會通過事件機制廣播給相應的其他的Bundle;一般來說都爲通過在Bundle中編寫初始需要註冊的服務的方法來完成Bundle可供外部使用的服務的暴露功能;如需要調用其他Plugin提供的服務可通過context的getServiceReference先獲取Service的句柄,再通過context.getService(ServiceReference)的方法獲取Service的實體。

Eclipse Plugin定義
Eclipse中的Plugin的概念爲包含一系列服務的模塊即爲一個Plugin。既然是遵循OSGI的,也就意味着Plugin通常是由Bundle和N多Service共同構成的,在此基礎上Eclipse認爲Plugin之間通常存在兩種關係,一種爲依賴,一種爲擴展,對於依賴可通過OSGI中元描述信息裏添加需要引用的Plugin即可實現,但擴展在OSGI中是沒有定義的,Eclipse採用了一個Extension Point的方式來實現Plugin的擴展功能。
結合OSGI
Eclipse遵循OSGI對於Plugin的ID、版本、提供商、classpath、所依賴的plugin以及可暴露對外的包均在manifest.mf文件中定義。
Plugin Extension Point
對於擴展,Eclipse採用Extension Point的方式來實現,每個Plugin可定義自己的Extension Point,同時也可實現其他Plugin的Extension Point,由於這個在OSGI中是未定義的,在Eclipse中仍然通過在plugin.xml中進行描述,描述的方法爲通過<extension-point id="" name="" schema="">的形式來定義Plugin的擴展點,通過<extension point="">的形式來定義實現的其他Plugin的擴展點,所提供的擴展點通過schema的方式進行描述,詳細見eclipse extension-point schema規範,爲了更好的說明擴展點這個概念,舉例如下,如工具欄就是工具欄Plugin提供的一個擴展點,其他的Plugin可通過此擴展點添加按鈕至工具欄中,並可相應的添加按鈕所對應的事件(當然,此事件必須實現工具欄Plugin此擴展點所要求的接口),工具欄的Plugin將通過callback的方式來相應的響應按鈕的動作。可見通過Extension Point的方式可以很好的提供Plugin的擴展方式以及實現擴展的方式。

Eclipse Plugin Framework
那麼Eclipse是如何做到Plugin機制的實現的呢??還是先講講Eclipse的設計風格,Eclipse在設計時有個重要的分層法則,即語言層相關和語言層無關的代碼分開(如jdt.core和core),核心與UI分開(如workbench.ui和workbench.core)這兩個分層法則,這個在Eclipse代碼中處處可見,在Plugin Framework部分也充分得體現了這個,遵循OSGI,Eclipse首先是實現了一個OSGI Impl,這個主要通過它的FrameWork、BundleHost、ServiceRegistry、BundleContextImpl等對象來實現,如果關心的話大家可以看看這部分的代碼,實現了Bundle的安裝、觸發、卸載以及Service的註冊、卸載、調用,在Plugin機制上Eclipse採用的爲lazy load的方式,即在調用時才進行實際的啓動,採用的爲句柄/實體的方式來實現,外部則通過OSGI進行啓動、停止等動作,各Plugin則通過BundleContext來進行服務的註冊、卸載和調用,這是OSGI的部分實現的簡單介紹。
那麼Extension Point方面Eclipse是如何實現的呢,在加載Plugin時,Eclipse通過對plugin.xml的解析獲取其中的<extension-point>節點和<extension>節點,並相應的註冊到ExtensionRegistry中,而各個提供擴展點的Plugin在提供擴展點的地方進行處理,如工具欄Plugin提供了工具欄的擴展點,那麼在構成工具欄時Plugin將通過Platform.getPluginRegistry().getExtensionPoint(擴展點ID)的方法獲取所有實現此擴展點的集合IExtensionPoint[],通過此集合可獲取IConfigurationElement[],而通過這個就可以獲取<extension point="">其中的配置,同時還可通過IConfigurationElement創建回調對象的實例,通過這樣的方法Eclipse也就實現了對於Plugin的擴展以及擴展的功能的回調。在Plugin Framework中還涉及很多事件機制的使用,比如Framework的事件機制,以便在Bundle註冊、Service註冊的時候進行通知。

總結
通過對Eclipse啓動過程的分析,可清晰的看到Eclipse Kernel+Core Plugins+Application Plugins的方式,在代碼中分別對應爲loadBasicBundles和registerApplicationServices,loadBasicBundles通過加載config.ini中的osgi.bundles完成基本的bundles的加載,去看看這個配置會發現是org.eclipse.core.runtime還有一個update,core.runtime又會通過IDEApplication來完成整個Eclipse的啓動,同時會註冊所有與workbench相關的plugin。
Eclipse由於以前版本的Plugin Framework是沒有采用OSGI的,所以通過EclipseAdaptor的方式來實現與以往的兼容,目前新的Plugin採用的方式基本就是manifest.mf描述Plugin OSGI部分的信息,Plugin.xml描述擴展點的信息。
Eclipse中有非常多優秀的設計,這個在看它的代碼時會有很深的感觸,比如Contributing to Eclipse中提到的Extension Object/Interface的設計,確實是非常的不錯,雖然看到你可能覺得很簡單,關鍵是要想得到併合適的去使用。
總結陳詞,^_^,Eclipse Plugin Framework是採用OSGI Impl+Plugin Extension-Point的方式來共同實現的,實現了Plugin的部署、編寫、獨立的Classloader和Context、Plugin中Service的註冊、Plugin中Service的調用、Plugin的依賴、Plugin的擴展、Plugin生命週期的管理。

帶來的思考
Eclipse Plugin Framework採用的是OSGI的實現,一定程度上我們也能看到OSGI的優點,那麼JMX+IoC方式的Plugin Framework與其的比較又是在哪些方面呢?Eclipse Plugin Framework不足的地方又在哪裏呢?哪些地方值得改進呢?

引自: BlueDavy之技術Blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章