概述
Eclipse中最出彩的部分莫過(guò)于它的Plugin Framework,,可以說(shuō)Eclipse在一定程度上使得Plugin機(jī)制得以流行,當(dāng)然,,Eclipse的優(yōu)勢(shì)不僅僅在此,,但正因?yàn)椴捎昧薖lugin機(jī)制,Eclipse才得以被不斷的擴(kuò)充,,越來(lái)越強(qiáng)大,。一直以來(lái)就想分析Eclipse的Plugin Framework,由于各種原因一直耽擱,,剛好這個(gè)周末沒(méi)什么事,,下定決心對(duì)其進(jìn)行了研究和分析,方法很原始,,就是對(duì)Eclipse的啟動(dòng)過(guò)程進(jìn)行分析,,基于的是Eclipse 3.1的版本,,分析過(guò)程就不在這說(shuō)了,主要是說(shuō)說(shuō)分析出來(lái)的心得,。
架構(gòu)上來(lái)講Eclipse基本采用的是Kernel+Core Plugins+Custom Plugins的結(jié)構(gòu)體系,,除了Kernel部分外均為Plugin,所以可稱(chēng)為all are plugins,,凡是Plugin的部分都是可被替換的,。
OSGI
Eclipse 3.0后采用的是OSGI來(lái)作為其Plugin Architecture實(shí)現(xiàn)的依據(jù),鑒于此就得簡(jiǎn)單提提OSGI了,,主要從Plugin的角度來(lái)分析OSGI,,OSGI概念中主要分為了Bundle和Service,可以認(rèn)為Bundle是一個(gè)模塊的管理器,,主要是通過(guò)BundleActivator管理模塊的生命周期,,而Service則是這個(gè)模塊可暴露對(duì)外的服務(wù)對(duì)象,這里體現(xiàn)了OSGI和傳統(tǒng)的Plugin Framework不同的一個(gè)地方,,管理和靜態(tài)結(jié)構(gòu)分開(kāi),,在OSGI中通過(guò)在manifest.mf文件中增加一些內(nèi)容來(lái)發(fā)布Bundle,在其中描述了Bundle的提供商,、版本,、唯一ID、classpath,、暴露對(duì)外的包,、所依賴(lài)的包;每個(gè)Bundle擁有自己的ClassLoader以及context,,通過(guò)context可進(jìn)行服務(wù)的注冊(cè),、卸載等,這些操作都會(huì)通過(guò)事件機(jī)制廣播給相應(yīng)的其他的Bundle,;一般來(lái)說(shuō)都為通過(guò)在Bundle中編寫(xiě)初始需要注冊(cè)的服務(wù)的方法來(lái)完成Bundle可供外部使用的服務(wù)的暴露功能,;如需要調(diào)用其他Plugin提供的服務(wù)可通過(guò)context的getServiceReference先獲取Service的句柄,再通過(guò)context.getService(ServiceReference)的方法獲取Service的實(shí)體,。
Eclipse Plugin定義
Eclipse中的Plugin的概念為包含一系列服務(wù)的模塊即為一個(gè)Plugin。既然是遵循OSGI的,,也就意味著Plugin通常是由Bundle和N多Service共同構(gòu)成的,,在此基礎(chǔ)上Eclipse認(rèn)為Plugin之間通常存在兩種關(guān)系,一種為依賴(lài),,一種為擴(kuò)展,,對(duì)于依賴(lài)可通過(guò)OSGI中元描述信息里添加需要引用的Plugin即可實(shí)現(xiàn),但擴(kuò)展在OSGI中是沒(méi)有定義的,,Eclipse采用了一個(gè)Extension Point的方式來(lái)實(shí)現(xiàn)Plugin的擴(kuò)展功能,。
結(jié)合OSGI
Eclipse遵循OSGI對(duì)于Plugin的ID,、版本、提供商,、classpath,、所依賴(lài)的plugin以及可暴露對(duì)外的包均在manifest.mf文件中定義。
Plugin Extension Point
對(duì)于擴(kuò)展,,Eclipse采用Extension Point的方式來(lái)實(shí)現(xiàn),,每個(gè)Plugin可定義自己的Extension Point,同時(shí)也可實(shí)現(xiàn)其他Plugin的Extension Point,,由于這個(gè)在OSGI中是未定義的,,在Eclipse中仍然通過(guò)在plugin.xml中進(jìn)行描述,描述的方法為通過(guò)<extension-point id="" name="" schema="">的形式來(lái)定義Plugin的擴(kuò)展點(diǎn),,通過(guò)<extension point="">的形式來(lái)定義實(shí)現(xiàn)的其他Plugin的擴(kuò)展點(diǎn),,所提供的擴(kuò)展點(diǎn)通過(guò)schema的方式進(jìn)行描述,詳細(xì)見(jiàn)eclipse extension-point schema規(guī)范,,為了更好的說(shuō)明擴(kuò)展點(diǎn)這個(gè)概念,,舉例如下,如工具欄就是工具欄Plugin提供的一個(gè)擴(kuò)展點(diǎn),,其他的Plugin可通過(guò)此擴(kuò)展點(diǎn)添加按鈕至工具欄中,,并可相應(yīng)的添加按鈕所對(duì)應(yīng)的事件(當(dāng)然,此事件必須實(shí)現(xiàn)工具欄Plugin此擴(kuò)展點(diǎn)所要求的接口),,工具欄的Plugin將通過(guò)callback的方式來(lái)相應(yīng)的響應(yīng)按鈕的動(dòng)作,。可見(jiàn)通過(guò)Extension Point的方式可以很好的提供Plugin的擴(kuò)展方式以及實(shí)現(xiàn)擴(kuò)展的方式,。
Eclipse Plugin Framework
那么Eclipse是如何做到Plugin機(jī)制的實(shí)現(xiàn)的呢,??還是先講講Eclipse的設(shè)計(jì)風(fēng)格,,Eclipse在設(shè)計(jì)時(shí)有個(gè)重要的分層法則,,即語(yǔ)言層相關(guān)和語(yǔ)言層無(wú)關(guān)的代碼分開(kāi)(如jdt.core和core),核心與UI分開(kāi)(如workbench.ui和workbench.core)這兩個(gè)分層法則,,這個(gè)在Eclipse代碼中處處可見(jiàn),,在Plugin Framework部分也充分得體現(xiàn)了這個(gè),遵循OSGI,,Eclipse首先是實(shí)現(xiàn)了一個(gè)OSGI Impl,,這個(gè)主要通過(guò)它的FrameWork、BundleHost,、ServiceRegistry,、BundleContextImpl等對(duì)象來(lái)實(shí)現(xiàn),如果關(guān)心的話(huà)大家可以看看這部分的代碼,實(shí)現(xiàn)了Bundle的安裝,、觸發(fā),、卸載以及Service的注冊(cè)、卸載,、調(diào)用,,在Plugin機(jī)制上Eclipse采用的為lazy load的方式,即在調(diào)用時(shí)才進(jìn)行實(shí)際的啟動(dòng),,采用的為句柄/實(shí)體的方式來(lái)實(shí)現(xiàn),,外部則通過(guò)OSGI進(jìn)行啟動(dòng)、停止等動(dòng)作,,各Plugin則通過(guò)BundleContext來(lái)進(jìn)行服務(wù)的注冊(cè),、卸載和調(diào)用,這是OSGI的部分實(shí)現(xiàn)的簡(jiǎn)單介紹,。
那么Extension Point方面Eclipse是如何實(shí)現(xiàn)的呢,,在加載Plugin時(shí),Eclipse通過(guò)對(duì)plugin.xml的解析獲取其中的<extension-point>節(jié)點(diǎn)和<extension>節(jié)點(diǎn),,并相應(yīng)的注冊(cè)到ExtensionRegistry中,,而各個(gè)提供擴(kuò)展點(diǎn)的Plugin在提供擴(kuò)展點(diǎn)的地方進(jìn)行處理,如工具欄Plugin提供了工具欄的擴(kuò)展點(diǎn),,那么在構(gòu)成工具欄時(shí)Plugin將通過(guò)Platform.getPluginRegistry().getExtensionPoint(擴(kuò)展點(diǎn)ID)的方法獲取所有實(shí)現(xiàn)此擴(kuò)展點(diǎn)的集合IExtensionPoint[],,通過(guò)此集合可獲取IConfigurationElement[],而通過(guò)這個(gè)就可以獲取<extension point="">其中的配置,,同時(shí)還可通過(guò)IConfigurationElement創(chuàng)建回調(diào)對(duì)象的實(shí)例,,通過(guò)這樣的方法Eclipse也就實(shí)現(xiàn)了對(duì)于Plugin的擴(kuò)展以及擴(kuò)展的功能的回調(diào)。在Plugin Framework中還涉及很多事件機(jī)制的使用,,比如Framework的事件機(jī)制,,以便在Bundle注冊(cè)、Service注冊(cè)的時(shí)候進(jìn)行通知,。
總結(jié)
通過(guò)對(duì)Eclipse啟動(dòng)過(guò)程的分析,,可清晰的看到Eclipse Kernel+Core Plugins+Application Plugins的方式,在代碼中分別對(duì)應(yīng)為loadBasicBundles和registerApplicationServices,,loadBasicBundles通過(guò)加載config.ini中的osgi.bundles完成基本的bundles的加載,,去看看這個(gè)配置會(huì)發(fā)現(xiàn)是org.eclipse.core.runtime還有一個(gè)update,core.runtime又會(huì)通過(guò)IDEApplication來(lái)完成整個(gè)Eclipse的啟動(dòng),,同時(shí)會(huì)注冊(cè)所有與workbench相關(guān)的plugin,。
Eclipse由于以前版本的Plugin Framework是沒(méi)有采用OSGI的,所以通過(guò)EclipseAdaptor的方式來(lái)實(shí)現(xiàn)與以往的兼容,,目前新的Plugin采用的方式基本就是manifest.mf描述Plugin OSGI部分的信息,Plugin.xml描述擴(kuò)展點(diǎn)的信息。
Eclipse中有非常多優(yōu)秀的設(shè)計(jì),,這個(gè)在看它的代碼時(shí)會(huì)有很深的感觸,,比如Contributing to Eclipse中提到的Extension Object/Interface的設(shè)計(jì),確實(shí)是非常的不錯(cuò),,雖然看到你可能覺(jué)得很簡(jiǎn)單,,關(guān)鍵是要想得到并合適的去使用。
總結(jié)陳詞,,^_^,,Eclipse Plugin Framework是采用OSGI Impl+Plugin Extension-Point的方式來(lái)共同實(shí)現(xiàn)的,實(shí)現(xiàn)了Plugin的部署,、編寫(xiě),、獨(dú)立的Classloader和Context、Plugin中Service的注冊(cè),、Plugin中Service的調(diào)用,、Plugin的依賴(lài)、Plugin的擴(kuò)展,、Plugin生命周期的管理,。
帶來(lái)的思考
Eclipse Plugin Framework采用的是OSGI的實(shí)現(xiàn),一定程度上我們也能看到OSGI的優(yōu)點(diǎn),,那么JMX+IoC方式的Plugin Framework與其的比較又是在哪些方面呢,?Eclipse Plugin Framework不足的地方又在哪里呢?哪些地方值得改進(jìn)呢,?