6.2.1 運(yùn)行時
鑒于在發(fā)布周期的一系列重大變化,Eclipse 3.0可能是最重要的釋放版本。在3.0之前的Eclipse架構(gòu)中,Eclipse由插件構(gòu)成的組件模型在互相交互上有兩種方式。首先,通過在它們的plugin.xml中使用requires語句來表達(dá)依賴。如果插件A依賴插件B,按照J(rèn)ava類的可見性約定,插件B中的所有Java類和資源對插件A來說都是可見的。每個插件都會有一個版本號,它們也可以指定依賴的版本號。其次,組件模型提供了擴(kuò)展和擴(kuò)展點(diǎn)機(jī)制。歷史上,Eclipse的提交者為Eclipse SDK編寫了自己的運(yùn)行環(huán)境來管理類加載器、插件依賴以及擴(kuò)展和擴(kuò)展點(diǎn)。
Equinox 在Eclipse中最初是一個孵化項(xiàng)目。Equinox 的目標(biāo)是取代已有的Eclipse組件模型,并提供對動態(tài)插件的支持。納入考慮的方案包括JMX、Jakarta Avalon以及OSGi。鑒于JMX并不是成熟的組件模型,所以不是合適的方案。沒有選擇Jakarta Avalon是因?yàn)樗鳛橐粋€項(xiàng)目已經(jīng)失去了發(fā)展的勢頭。除了技術(shù)需要,支持這些技術(shù)的社區(qū)也同等重要。他們是否會愿意接受Eclipse選定的變化?是否能夠得到積極的發(fā)展和更廣泛的接受?Equinox 團(tuán)隊(duì)認(rèn)為他們最終所選擇技術(shù)的社區(qū)與技術(shù)考量本身一樣重要。
在研究和評估可行的選擇后,提交者選擇了OSGi。為什么是OSGi?它有一個語義化的版本模式來管理依賴。它提供了JDK本身所缺乏的模塊化框架。對其它bundle可見的包需要明確進(jìn)行導(dǎo)出,而其它的將會被隱藏。OSGi提供了自己的類加載器,所以Equinox 團(tuán)隊(duì)不需要再維護(hù)自己的了。通過標(biāo)準(zhǔn)化Eclipse生態(tài)系統(tǒng)之外那些已被廣泛采用的組件模型,他們認(rèn)為會吸引到更廣泛的社區(qū)支持并且Eclipse會被更多的采用。
Equinox 團(tuán)隊(duì)對OSGi充滿活力的社區(qū)感到滿意,他們可以與這個社區(qū)合作來實(shí)現(xiàn)Eclipse需要的組件模型功能。例如,當(dāng)時的OSGi只支持在包級別列出依賴并不支持Eclipse需要的插件級別。另外,OSGi當(dāng)時還沒有片段(fragment)的理念,而這是Eclipse為已存在的插件在某平臺或環(huán)境上提供特定代碼的機(jī)制。例如,提供運(yùn)行在Linux或Windows文件系統(tǒng)上的片段以及提供語言翻譯的片段。一旦確定采用OSGi作為新的運(yùn)行環(huán)境,提交者需要一個開源的框架實(shí)現(xiàn)。他們評估了Oscar(Apache Felix的前身)以及IBM開發(fā)的服務(wù)管理框架(Service Management Framework,SMF)。當(dāng)時,Oscar是一個沒有被廣泛采用的研究項(xiàng)目。他們最終選擇了SMF,因?yàn)樗呀?jīng)用在一些產(chǎn)品上并達(dá)到了企業(yè)應(yīng)用的水準(zhǔn)。Equinox實(shí)現(xiàn)現(xiàn)在是OSGi規(guī)范的參考實(shí)現(xiàn)。
為了保證已有的插件能夠在3.0安裝環(huán)境中依舊好用,Eclipse提供了一個兼容層。如果為了適應(yīng)3.0底層架構(gòu)的變化而要求開發(fā)者重寫他們的插件,那將會影響到Eclipse作為一個工具平臺的發(fā)展勢頭。Eclipse消費(fèi)者的期望是這個平臺依舊好用。
切換到OSGi后,Eclipse的插件被稱為bundle。插件和bundle是一回事。他們都提供了一個模塊化的功能子集并在manifest中包含了子描述的元數(shù)據(jù)信息。在之前,依賴、導(dǎo)出包以及擴(kuò)展和擴(kuò)展點(diǎn)都在plugin.xml中進(jìn)行描述。改為OSGi的bundle后,擴(kuò)展和擴(kuò)展點(diǎn)還是在plugin.xml中進(jìn)行描述,因?yàn)樗鼈兪荅clipse的概念。其它的信息在OSGi版本的bundle manifest文件META-INF/MANIFEST.MF中進(jìn)行描述。為了適應(yīng)這種變化,PDE在Eclipse中提供了一個新的manifest編輯器。每個bundle都有名字和版本。org.eclipse.ui這個bundle的manifest如下:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Plugin.name
Bundle-SymbolicName: org.eclipse.ui; singleton:=true
Bundle-Version: 3.3.0.qualifier
Bundle-ClassPath: .
Bundle-Activator: org.eclipse.ui.internal.UIPlugin
Bundle-Vendor: %Plugin.providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.ui.internal;x-internal:=true
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)",
org.eclipse.swt;bundle-version="[3.3.0,4.0.0)";visibility:=reexport,
org.eclipse.jface;bundle-version="[3.3.0,4.0.0)";visibility:=reexport,
org.eclipse.ui.workbench;bundle-version="[3.3.0,4.0.0)";visibility:=reexpot,
org.eclipse.core.expressions;bundle-version="[3.3.0,4.0.0)"
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0, J2SE-1.3
在Eclipse 3.1中,manifest還能指定bundle需要的執(zhí)行環(huán)境(bundle required execution environment,BREE)。執(zhí)行環(huán)境指定了bundle運(yùn)行所需要的最低Java環(huán)境信息。Java編譯器并不能理解bundle和OSGi manifest。PDE提供了開發(fā)OSGi bundle的工具。所以,PDE解析bundle的manifest并生成bundle的classpath。如果在你的manifest中聲明了J2SE-1.4的執(zhí)行環(huán)境,然后編寫一些包含注解的代碼的話,那在你的代碼中將會提示編譯錯誤。這能夠保證你的代碼遵循你在manifest中聲明的協(xié)議。
OSGi為Java提供了一個模塊化框架。OSGi框架管理一系列子描述的bundle及其類加載機(jī)制功能。每個bundle都有自己的類加載器。對于bundle來說,其可見的類路徑是通過檢查其manifest的依賴構(gòu)建的。因此,manifest描述了bundle導(dǎo)出的包,這些包對客戶端可見就像公共API對調(diào)用者可見一樣。使用這些API的bundle必須相應(yīng)地導(dǎo)入需要包。另外,manifest允許聲明依賴的版本??匆幌律厦鎚anifest中的Require-Bundle信息,你會發(fā)現(xiàn)org.eclipse.ui依賴的org.eclipse.core.runtime bundle的版本必須大于等于3.2.0并且小于4.0.0。
圖6.5 版本命名模式
基于OSGi的版本命名模式,每個bundle有一個名字和四部分版本號所組成的唯一標(biāo)示。對用戶來講,id和版本號組合起來代表了一組唯一的字節(jié)。按照Eclipse的慣例,如果對bundle進(jìn)行了修改,用戶根據(jù)版本號某一部分的變化能夠判斷了變化的類型。因此,如果你想表示API的破壞性變化,你要增加第一部分(主版本)的值。如果你只是增加API,你需要增加第二部分(小版本)的值。如果只是修改缺陷不影響API,需要增加第三部分(服務(wù)版本)的值。最后,第四部分或所謂的限定部分用來表示基于源碼控制庫的構(gòu)建id。
除了能夠指定bundle間的固定依賴,OSGi還有一套服務(wù)(service)的機(jī)制,它支持bundle間進(jìn)一步解耦合。服務(wù)也是對象,它會把一些屬性注冊在OSGi服務(wù)注冊器中。不同于擴(kuò)展點(diǎn),服務(wù)是動態(tài)注冊的,而擴(kuò)展點(diǎn)是在Eclipse啟動的時候通過掃描bundle注冊到擴(kuò)展點(diǎn)注冊器中的。需要使用服務(wù)的bundle需要將定義服務(wù)協(xié)議的包導(dǎo)入進(jìn)來,框架根據(jù)服務(wù)注冊器來確定使用哪個服務(wù)實(shí)現(xiàn)。
就像Java類文件中的主方法,會有一個特殊的應(yīng)用來定義Eclipse的啟動。Eclipse應(yīng)用的通過擴(kuò)展點(diǎn)來定義。例如,啟動Eclipse IDE本身的應(yīng)用是org.eclipse.ui.ide.workbench,它是在org.eclipse.ui.ide.application中定義的:
<plugin>
<extension
id="org.eclipse.ui.ide.workbench"
point="org.eclipse.core.runtime.applications">
<application>
<run
class="org.eclipse.ui.internal.ide.application.IDEApplication">
</run>
</application>
</extension>
</plugin>
Eclipse提供了很多的應(yīng)用,例如運(yùn)行獨(dú)立幫助服務(wù)器的,Ant任務(wù)的以及JUnit測試的等。
6.2.2 富客戶端平臺(Rich Client Platform,RCP)
開源社區(qū)工作的最有意思的一件事就是用戶可以以你完全預(yù)想不到的方式來使用軟件。Eclipse的初衷是提供一個平臺和工具來創(chuàng)建和擴(kuò)展IDE。但是,在3.0版本要發(fā)布的時候,從缺陷報告來看,社區(qū)用戶有人用了平臺bundle中的一部分來構(gòu)建富客戶端平臺(RCP)應(yīng)用。因?yàn)镋clipse原來是以IDE為中心的視角來創(chuàng)建的,它需要做一些重構(gòu)來允許社區(qū)用戶更便利地應(yīng)用于這種場景。RCP應(yīng)用不需要IDE相關(guān)的功能,所以為了讓社區(qū)用戶構(gòu)建RCP應(yīng)用,他們將幾個bundle分離了出來并組成了一個更小的集合。?
圖6.7 Eclipse 3.3 SDK的特性層級
如果你只想更新Eclipse中的某一個bundle到新版本,整個特性需要被更新,因?yàn)檫@是更新管理器所采用的粗粒度機(jī)制。為了一個bundle而更新特性是低效的。
在工作空間中,你可以使用PDE向?qū)韯?chuàng)建并構(gòu)建特性。文件feature.xml定義了特性中包含的bundle以及bundle的一些簡單屬性。像bundle一樣,特性也有名字和版本。特性可以包含其它的特性,并且可以指定其所包含特性的版本范圍。包含在特性中的bundle會被羅列出來并附帶一些屬性。例如,你可以查看片段org.eclipse.launcher.gtk.linux.x86_64指定了它所使用的操作系統(tǒng)(os)、窗口系統(tǒng)(ws)以及架構(gòu)(arch)。所以,當(dāng)更新到新版本的時候,這個片段只能安裝在這個平臺上。這些平臺相關(guān)的過濾條件包含在bundle的OSGi manifest中。
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="org.eclipse.rcp"
label="%featureName"
version="3.7.0.qualifier"
provider-name="%providerName"
plugin="org.eclipse.rcp"
image="eclipse_update_120.jpg">
<description>
%description
</description>
<copyright>
%copyright
</copyright>
<license url="%licenseURL">
%license
</license>
<plugin
id="org.eclipse.equinox.launcher"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="org.eclipse.equinox.launcher.gtk.linux.x86_64"
os="linux"
ws="gtk"
arch="x86_64"
download-size="0"
install-size="0"
version="0.0.0"
fragment="true"/>
Eclipse應(yīng)用不僅包含特性和bundle。還有平臺相關(guān)的執(zhí)行文件來啟動Eclipse自身、許可證文件以及平臺相關(guān)的類庫,就像以下列表中的Eclipse應(yīng)用中包含的文件。
com.ibm.icu
org.eclipse.core.commands
org.eclipse.core.conttenttype
org.eclipse.core.databinding
org.eclipse.core.databinding.beans
org.eclipse.core.expressions
org.eclipse.core.jobs
org.eclipse.core.runtime
org.eclipse.core.runtime.compatibility.auth
org.eclipse.equinox.common
org.eclipse.equinox.launcher
org.eclipse.equinox.launcher.carbon.macosx
org.eclipse.equinox.launcher.gtk.linux.ppc
org.eclipse.equinox.launcher.gtk.linux.s390
org.eclipse.equinox.launcher.gtk.linux.s390x
org.eclipse.equinox.launcher.gtk.linux.x86
org.eclipse.equinox.launcher.gtk.linux.x86_64
這些文件不能通過更新管理器來更新,同樣是因?yàn)樗荒芴幚硖匦?。鑒于這些文件在每個主版本釋放的時候都會更新,這就意味著每當(dāng)有新版本的時候,用戶必須下載一個新的zip包而不是更新已有的安裝。這對于Eclipse社區(qū)來講是難以接受的。PDE支持通過產(chǎn)品文件來指明構(gòu)建RCP應(yīng)用需要的所有文件。但是,更新管理器并沒有一種機(jī)制將這些文件自動提供到你的安裝程序中,這讓用戶和產(chǎn)品開發(fā)人員都很沮喪。在2008年3月,p2作為新的提供方案(provisioning solution)放到了SDK中。為了向后兼容,更新管理器依舊可用,但是默認(rèn)啟動的是p2。
6.3.1 p2的理念
Equinox p2完全是關(guān)于安裝單元的(installation unit,IU)。IU是要安裝工件的id和名字的描述。這個元數(shù)據(jù)也描述了工件的功能(提供了什么)和需求(它的依賴)。如果工件只用于特定的環(huán)境,元數(shù)據(jù)也能表達(dá)適用范圍的過濾信息。例如,org.eclipse.swt.gtk.linux.x86片段只能用于Linux gtk x86機(jī)器。從根本上來講,元數(shù)據(jù)就是bundle的manifest信息的表達(dá)。而工件是要安裝的二進(jìn)制位。通過分離元數(shù)據(jù)和它所描述的工件,實(shí)現(xiàn)了關(guān)注點(diǎn)的分離。p2倉庫需要包含元數(shù)據(jù)和工件庫。
更多建議: