了解 Eclipse 插件如何使用 OSGi

Eclipse 和 OSGi 的關(guān)系,從 plugin.xml 到 manifest.mf

級(jí)別: 中級(jí) 原帖地址:http://www.ibm.com/developerworks/cn/opensource/os-ecl-osgi/index.html

Scott Delap (scott@clientjava.com), Desktop/Enterprise Java 顧問(wèn)

Eclipse 集成開(kāi)發(fā)環(huán)境(IDE)和 Eclipse Rich Client Platform(RCP)應(yīng)用程序的核心由 Open Services Gateway Initiative(OSGi)規(guī)范的實(shí)現(xiàn)驅(qū)動(dòng)。本文通過(guò)描述對(duì) Eclipse 平臺(tái)而言插件是什么,并跟蹤從 Eclipse V2.1 到今天基于 OSGi 的實(shí)現(xiàn)中插件的發(fā)展,闡明了 Eclipse 與 OSGi 的關(guān)系。還解釋了 OSGi manifest.mf 文件選項(xiàng)以及通過(guò) Eclipse 提供的添加項(xiàng)。

大多數(shù) Java? 編程語(yǔ)言開(kāi)發(fā)人員通過(guò)作為 IDE 的功能認(rèn)識(shí)了 Eclipse。Eclipse IDE 實(shí)際上由叫做插件 的交互式組件的集合組成。這些插件組成了 IDE 的基礎(chǔ),它們還可用于創(chuàng)建其他桌面應(yīng)用程序。創(chuàng)建基于 Eclipse 的應(yīng)用程序所需的最小插件集稱為 Eclipse Rich Client Platform(RCP)。但是,插件本身不能啟動(dòng)。它們需要在一個(gè)環(huán)境中啟動(dòng)和操作。Eclipse 使用 OSGi R4 規(guī)范的實(shí)現(xiàn)提供了該環(huán)境。

因?yàn)?Eclipse 在本質(zhì)上是由 OSGi 驅(qū)動(dòng)的,因此必須了解 Eclipse 插件的概念與 OSGi 框架有什么關(guān)系。在本文中,我將通過(guò)描述對(duì) Eclipse 平臺(tái)而言插件是什么來(lái)詳細(xì)解釋這種關(guān)系。然后,將描述在 Eclipse V2.1 平臺(tái)到今天基于 OSGi 的實(shí)現(xiàn)中插件的發(fā)展。最后,將詳細(xì)介紹應(yīng)用于 Eclipse 插件的 OSGi 提供的 manifest.mf 選項(xiàng)。

插件是什么?

Eclipse 聯(lián)機(jī)幫助將插件定義為:

“插件是為系統(tǒng)提供功能的代碼和/或數(shù)據(jù)的結(jié)構(gòu)化包??梢砸源a庫(kù)(帶有公共 [應(yīng)用程序接口] API 的 Java 類)、平臺(tái)擴(kuò)展甚至文檔的形式來(lái)提供功能。插件可以定義擴(kuò)展點(diǎn)、定義良好的位置,其他插件可以在這些位置添加功能?!?/blockquote>

要注意的一個(gè)重點(diǎn)是插件以結(jié)構(gòu)化方式提供功能。它們可以提供服務(wù)(比如日志)或可用于用戶界面(UI)的功能,比如編輯器。不管什么功能,所有插件都以相同的結(jié)構(gòu)化方式來(lái)定義。

到 OSGi 的發(fā)展

如前所述,Eclipse 使用 OSGi 作為插件系統(tǒng)的基礎(chǔ)。但并非總是如此。早期版本的 Eclipse 也設(shè)計(jì)為插件集合,而且 Eclipse 包括自己專用的插件系統(tǒng)來(lái)管理交互。但是,隨著 Eclipse IDE 要求的增長(zhǎng),必須需要一個(gè)更強(qiáng)壯的解決方案。這個(gè)新系統(tǒng)的基本要求包括動(dòng)態(tài)添加新插件和停止現(xiàn)有插件的能力。經(jīng)過(guò)大量研究之后,Eclipse 創(chuàng)建者決定通過(guò)實(shí)現(xiàn) OSGi 框架規(guī)范替換專用的插件框架。

OSGi 是服務(wù)平臺(tái)的規(guī)范。Eclipse 提供了該規(guī)范的許多可用實(shí)現(xiàn)之一,并用作最新 OSGi R4 規(guī)范的參考實(shí)現(xiàn)。OSGi 是基于 Java 的框架,旨在用于需要長(zhǎng)運(yùn)行時(shí)間、動(dòng)態(tài)更新和對(duì)運(yùn)行環(huán)境破壞最小的系統(tǒng)。起初,OSGi 旨在用于家庭自動(dòng)化和家庭網(wǎng)關(guān)設(shè)備。最近,從手機(jī)到汽車都發(fā)現(xiàn)了它的蹤跡。

在核心,OSGi 是一個(gè)組件和服務(wù)模型,如圖 1 所示。OSGi 規(guī)范定義了一個(gè)叫做綁定包 的模塊化單位。(在下文中,除非特別指明,Eclipse 術(shù)語(yǔ)插件 和 OSGi 術(shù)語(yǔ)綁定包 可交換使用,因?yàn)樗?Eclipse 插件現(xiàn)在都是 OSGi 綁定包。)OSGi 還提供了 Java Virtual Machine(JVM)級(jí)別的服務(wù)注冊(cè),該綁定包可用于發(fā)布、發(fā)現(xiàn)和綁定至服務(wù)。

圖 1. 主機(jī)操作系統(tǒng)、Java 和 OSGi 中層的交互  主機(jī)操作系統(tǒng)、Java 和 OSGi 中層的交互

OSGi 規(guī)范定義了綁定包生命周期的基礎(chǔ)架構(gòu)和綁定包的交互方式。這些規(guī)則通過(guò)使用特殊 Java 類加載器來(lái)強(qiáng)制執(zhí)行。在一般 Java 應(yīng)用程序中,CLASSPATH 中的所有類都對(duì)所有其他類可見(jiàn)。相反,OSGi 類加載器基于 OSGi 規(guī)范和每個(gè)綁定包的 manifest.mf 文件中指定的選項(xiàng)(稍后將詳細(xì)介紹)來(lái)限制類交互。

Eclipse IDE 使用圍繞模塊化和綁定包生命周期的一個(gè) OSGi 子集。但是,它最低限度地使用了 OSGi 提供的服務(wù)支持。相反,Eclipse 提供自己的擴(kuò)展點(diǎn)系統(tǒng)來(lái)啟用綁定包交互。綁定包將功能暴露給其他擴(kuò)展。綁定包還定義自己的擴(kuò)展點(diǎn),允許其他綁定包向其貢獻(xiàn)功能。使用 Eclipse 中擴(kuò)展點(diǎn)的一個(gè)示例是 Preferences 窗口。核心 Eclipse 插件提供中央窗口,并暴露擴(kuò)展點(diǎn)以允許其他首選項(xiàng)頁(yè)面的貢獻(xiàn)。當(dāng)插件添加到 Eclipse 中時(shí),它們可以貢獻(xiàn)它們自己的頁(yè)面。Eclipse 中擴(kuò)展點(diǎn)的模型不同于基本的 OSGi 服務(wù)。綁定包擴(kuò)展點(diǎn)由定義綁定包擁有;其他綁定包只對(duì)這些點(diǎn)做貢獻(xiàn)。相反,任何綁定包可以實(shí)現(xiàn)和使用 OSGi 服務(wù)。

使用 OSGi 實(shí)現(xiàn) Eclipse

在 3.1 之前版本的 Eclipse 中,在每個(gè)插件的 plugin.xml 文件中定義插件依賴關(guān)系以及擴(kuò)展和擴(kuò)展點(diǎn)。在使用 OSGi 的新版本 Eclipse 中,依賴關(guān)系信息被分解到 manifest.mf 文件中,而 plugin.xml 文件只包含擴(kuò)展和擴(kuò)展點(diǎn)的 XML 定義。看一個(gè)演示該發(fā)展的生動(dòng)的工作示例十分有用。清單 1 展示了 Eclipse V3.0 中 org.eclipse.pde.ui 插件的代碼段。

清單 1. org.eclipse.pde 插件中的代碼段
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
   id="org.eclipse.pde.ui"
   name="%name"
   version="3.0.2"
   provider-name="%provider-name"
   class="org.eclipse.pde.internal.ui.PDEPlugin">

   <runtime>
      <library name="pdeui.jar">
         <export name="*"/>
      </library>

   </runtime>
   <requires>
      <import plugin="org.eclipse.core.runtime.compatibility"/>
      <import plugin="org.eclipse.ui.ide"/>
      <import plugin="org.eclipse.ui.views"/>
      <import plugin="org.eclipse.jface.text"/>

      <import plugin="org.eclipse.ui.workbench.texteditor"/>
      <import plugin="org.eclipse.ui.editors"/>
      <import plugin="org.eclipse.ant.core"/>
      <import plugin="org.eclipse.core.resources"/>
      <import plugin="org.eclipse.debug.core"/>
      <import plugin="org.eclipse.debug.ui"/>

      <import plugin="org.eclipse.help.base"/>
      <import plugin="org.eclipse.jdt.core"/>
      <import plugin="org.eclipse.jdt.debug.ui"/>
      <import plugin="org.eclipse.jdt.launching"/>
      <import plugin="org.eclipse.jdt.ui"/>
      <import plugin="org.eclipse.pde"/>

      <import plugin="org.eclipse.pde.build"/>
      <import plugin="org.eclipse.search"/>
      <import plugin="org.eclipse.team.core"/>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.update.core"/>
      <import plugin="org.eclipse.ui.forms"/>

      <import plugin="org.eclipse.ant.ui"/>
      <import plugin="org.eclipse.jdt.junit"/>
      <import plugin="org.eclipse.ui.intro"/>
      <import plugin="org.eclipse.ui.cheatsheets"/>
   </requires>


<!-- Extension points -->
   <extension-point id="pluginContent" 
   name="%expoint.pluginContent.name" 
   schema="schema/pluginContent.exsd"/>
   <extension-point id="newExtension" 
   name="%expoint.newExtension.name" 
   schema="schema/newExtension.exsd"/>
<extension-point id="templates" 
name="%expoint.templates.name" 
schema="schema/templates.exsd"/>
<extension-point id="samples" 
name="%expoint.samples.name" 
schema="schema/samples.exsd"/>

<!-- Extensions -->
   <extension
         point="org.eclipse.ui.perspectives">

      <perspective
            name="%perspective.name"
            icon="icons/eview16/plugins.gif"
            class="org.eclipse.pde.internal.ui.PDEPerspective"
            id="org.eclipse.pde.ui.PDEPerspective">
      </perspective>
   </extension>

<export name="*"/> 聲明暴露了插件中的所有包以供其他插件使用。插件依賴關(guān)系導(dǎo)入部分列出了 org.eclipse.pde.ui 插件需要的必備插件。

接下來(lái)兩部分定義了 org.eclipse.pde.ui 可用于其他插件的擴(kuò)展點(diǎn)以及它對(duì)其他插件的貢獻(xiàn)。在本例中,可以看到自定義 Eclipse Plug-in Development Environment(PDE)視圖的定義。

下面來(lái)看 Eclipse V3.1 中的同一插件定義。清單 2 展示了 plugin.xml 文件。

清單 2. Plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>

    
<!-- Extension points -->
   <extension-point id="pluginContent" 
   name="%expoint.pluginContent.name" 
   schema="schema/pluginContent.exsd"/>

   <extension-point id="newExtension" 
   name="%expoint.newExtension.name" 
   schema="schema/newExtension.exsd"/>
   <extension-point id="templates" 
   name="%expoint.templates.name" 
   schema="schema/templates.exsd"/>
   <extension-point id="samples" 
   name="%expoint.samples.name" 
   schema="schema/samples.exsd"/>

<!-- Extensions -->
   <extension
         point="org.eclipse.ui.perspectives">
      <perspective
            name="%perspective.name"
            icon="icons/eview16/plugins.gif"
            class="org.eclipse.pde.internal.ui.PDEPerspective"
            id="org.eclipse.pde.ui.PDEPerspective">

      </perspective>

注意,導(dǎo)出和導(dǎo)入信息不見(jiàn)了。該信息現(xiàn)在位于清單 3 所示的 manifest.mf 文件中。

清單 3. Manifest.mf
Manifest-Version: 1.0
Bundle-Name: %name
Bundle-SymbolicName: org.eclipse.pde.ui; singleton:=true
Bundle-Version: 3.1.0
Bundle-ClassPath: org.eclipse.pde.ui_3.1.0.jar
Bundle-Activator: org.eclipse.pde.internal.ui.PDEPlugin
Bundle-Vendor: %provider-name
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime,
 org.eclipse.ui.ide,
 org.eclipse.ui.views,
 org.eclipse.jface.text,
 org.eclipse.ui.workbench.texteditor,
 org.eclipse.ui.editors,
 org.eclipse.ant.core,
 org.eclipse.core.resources,
 org.eclipse.debug.core,
 org.eclipse.debug.ui,
 org.eclipse.jdt.core,
 org.eclipse.jdt.debug.ui,
 org.eclipse.jdt.launching,
 org.eclipse.jdt.ui,
 org.eclipse.pde,
 org.eclipse.pde.build,
 org.eclipse.search,
 org.eclipse.team.core,
 org.eclipse.ui,
 org.eclipse.update.core,
 org.eclipse.ui.forms,
 org.eclipse.ant.ui,
 org.eclipse.jdt.junit,
 org.eclipse.ui.intro,
 org.eclipse.ui.cheatsheets,
 org.eclipse.update.configurator,
 org.eclipse.help.base
Bundle-ManifestVersion: 2
Eclipse-AutoStart: true
Export-Package: org.eclipse.pde.internal.ui;x-internal:=true,
 org.eclipse.pde.internal.ui.build;x-internal:=true,

 . . .

 org.eclipse.pde.ui,
 org.eclipse.pde.ui.internal.samples;x-internal:=true,
 org.eclipse.pde.ui.templates

各種插件導(dǎo)入現(xiàn)在被指定為必需的綁定包,* 包導(dǎo)出已經(jīng)替換為顯式導(dǎo)出的包列表。

插件級(jí)的依賴關(guān)系改為需要顯式導(dǎo)出和導(dǎo)入包的依賴關(guān)系,當(dāng) Eclipse 宣布這個(gè)消息時(shí),曾引起大量騷動(dòng)。主要抱怨的是缺乏已經(jīng)存在于 Eclipse 早期版本中的 <export name="*"/> 的替代物。但是,該省略有許多原因。最重要的原因是從顯式導(dǎo)入和導(dǎo)出中獲得的速度收益。早期版本的 Eclipse 必須打開(kāi)并瀏覽每個(gè)插件 jar 文件以確定它包含哪些類。不包括 * 導(dǎo)出還提供了一級(jí)保護(hù)來(lái)避免插件暴露不必要的類。插件開(kāi)發(fā)人員必須進(jìn)行專門(mén)選擇來(lái)使插件中的功能可供外部使用。該限制允許內(nèi)部包保留在內(nèi)部。

OSGi 清單選項(xiàng)

OSGi R4 框架核心目前的規(guī)范草案幾乎有 PDF 格式的 300 頁(yè)。介紹該規(guī)范的每個(gè)部分超出了本文范圍,但我將討論 Eclipse 插件開(kāi)發(fā)人員特別感興趣的 OSGi manifest.mf 選項(xiàng):

Bundle-Activator
該類用于啟動(dòng)和停止綁定包。在上面的示例插件中,指定了 org.eclipse.pde.internal.ui.PDEPlugin 類。該類擴(kuò)展 org.eclipse.core.runtime.Plugin,實(shí)現(xiàn)了 BundleActivator 接口。
Bundle-ClassPath
該屬性指定要用于綁定包的 CLASSPATH。該屬性可以包含對(duì)綁定包 jar 文件中目錄或 jar 文件的引用??梢允褂镁潼c(diǎn)指明綁定包的根。在示例 Eclipse PDE 綁定包中,指定了綁定包 jar 文件中的 org.eclipse.pde.ui_3.1.0.jar。如果將插件的源版本導(dǎo)入工作區(qū)中,導(dǎo)入過(guò)程將更改綁定包 CLASSPATH 以顯示為 Bundle-ClassPath:,這允許插件的開(kāi)發(fā)版本挑選已編譯的綁定包類。
Bundle-Version
該屬性指定綁定包的版本號(hào)。包導(dǎo)入和必需的綁定包規(guī)范可以包括綁定包版本號(hào)。
Export-Package
該屬性指定要公共暴露給其他插件的所有包。
Import-Package
該屬性指定要從必需插件中顯式導(dǎo)入的所有包。默認(rèn)情況下,必須為要啟動(dòng)的綁定包解析所有包。還可以將包導(dǎo)入指定為可選項(xiàng),以支持包不存在的情況。顯式導(dǎo)入的類在 Require-Bundle 插件中的包之前解析。
Require-Bundle
該屬性指定要在給定綁定包中導(dǎo)入使用的綁定包及其已導(dǎo)出的包。指定的綁定包在顯式包導(dǎo)入之后解析。

Eclipse 提供的其他清單選項(xiàng)

伙伴類加載器選項(xiàng)

首先為 Hibernate 創(chuàng)建插件。然后創(chuàng)建一個(gè)插件,其中包含與 Hibernate 有依賴關(guān)系的特定于域的類。將下列行添加到 Hibernate 插件清單中:Eclipse-BuddyPolicy: registered。

將下列清單屬性添加到包含特定于域的類或資源的插件清單中: Eclipse-RegisterBuddy: hibernate

該行允許插件通過(guò)聲明將自己暴露給 Hibernate 插件,而它預(yù)先并不知道這些插件?,F(xiàn)在,Hibernate 插件可以看到需要的類,雖然它并沒(méi)有專門(mén)導(dǎo)入它們。

OSGi 規(guī)范包括的 manifest.mf 配置選項(xiàng)不提供 Eclipse 平臺(tái)需要的所有功能。因此,Eclipse 創(chuàng)建者添加了多個(gè)擴(kuò)展(還建議將它們包括在未來(lái)版本的 OSGi 規(guī)范中):

Export-Package 頭擴(kuò)展
Eclipse 具有兩個(gè) OSGi 解析器方法 —— defaultstrict,可以使用 osgi.resolver 屬性指定它們。Eclipse 還包括對(duì) Export-Package 屬性的兩個(gè)擴(kuò)展 —— x-internalx-friends,啟用 Strict 模式時(shí),會(huì)強(qiáng)制執(zhí)行這兩個(gè)擴(kuò)展。
x-internal
該屬性的默認(rèn)值是 false。當(dāng)使用該選項(xiàng)將內(nèi)部包指定為 true 時(shí),Eclipse PDE 禁止其使用。
x-friends
該選項(xiàng)類似于 x-internal,但允許特定綁定包使用具有該選項(xiàng)的已導(dǎo)出包。其他綁定包被禁止。x-internal 選項(xiàng)優(yōu)先于 x-friends
Eclipse-AutoStart
默認(rèn)情況下,Eclipse 根據(jù)需要加載綁定包。因此,當(dāng)導(dǎo)入綁定包包含的第一個(gè)類的綁定包需要這個(gè)類時(shí),就會(huì)加載這些綁定包。將該值指定為 ?? 會(huì)導(dǎo)致 Eclipse 在啟動(dòng)時(shí)加載綁定包。還可以指定例外情況列表,它們是無(wú)需啟動(dòng)包含它們的綁定包就可以加載的類和資源。
Eclipse-PlatformFilter
該屬性允許為要啟動(dòng)的綁定包指定必須等于 true 的條件。可以將下列信息包括在指定的表達(dá)式中:
  • osgi.nl,表示語(yǔ)言
  • osgi.os,表示操作系統(tǒng)
  • osgi.arch,表示架構(gòu)
  • osgi.ws,表示窗口系統(tǒng)
展示如何使用該屬性的一個(gè)示例是,在啟動(dòng)使用 SWT_AWT 橋的插件之前驗(yàn)證操作系統(tǒng)是否是 Mac OS X。(Standard Widget Toolkit(SWT)的 Mac OS X 實(shí)現(xiàn)當(dāng)前不支持該功能。)
Eclipse-BuddyPolicy
該選項(xiàng)指定加載綁定包策略的類。通常,綁定包只在其內(nèi)部類和從依賴綁定包中導(dǎo)入的內(nèi)部類中具有可見(jiàn)性。在 Eclipse 新聞組中用來(lái)解釋伙伴類加載的流行示例是 Hibernate。Hibernate 框架必須查看用戶創(chuàng)建的而非 Hibernate 本身一部分的類和資源。這樣的一種情況是當(dāng)使用項(xiàng)目動(dòng)態(tài)填充來(lái)自 Hibernate Query Language(HQL)查詢的類時(shí)。默認(rèn)情況下,Hibernate 將無(wú)法查看位于包含 Hibernate jar 文件的插件外部的類,而需要修改 Hibernate 插件以創(chuàng)建包含 Hibernate 地圖不可接受的類的每個(gè)插件。幸運(yùn)的是,伙伴類加載器選項(xiàng) 一節(jié)中介紹的伙伴類加載器選項(xiàng)解決了這個(gè)問(wèn)題。

Eclipse 和 OSGi 的未來(lái)趨勢(shì)

Eclipse 已經(jīng)從使用 OSGi 中大大受益,獲得了以動(dòng)態(tài)方式管理組件生命周期的一個(gè)健壯的系統(tǒng)。新的使用方法每天都在被發(fā)掘,比如服務(wù)器層特征 servlet、JavaServer Pages 以及 Eclipse 樣式插件中的其他 HTTP 資源。

Eclipse Foundation 已經(jīng)決定在驅(qū)動(dòng) OSGi 規(guī)范向前發(fā)展的過(guò)程中扮演關(guān)鍵角色,以便于自己和其他人利用 OSGi。在從專用 Eclipse 插件框架轉(zhuǎn)換到 OSGi 的過(guò)程中,對(duì) OSGi 規(guī)范進(jìn)行了許多添加,這些添加成了 OSGi R4 規(guī)范發(fā)行版的一部分。因此,Eclipse Equinox 項(xiàng)目已經(jīng)成為不斷發(fā)展的 OSGi 參考實(shí)現(xiàn)。該實(shí)現(xiàn)以及用于管理發(fā)展 OSGi 的 Java Specification Request(JSR) 291 的創(chuàng)建,保證了 Eclipse/OSGi 合作伙伴關(guān)系將在未來(lái)幾年里不斷取得成功。

Flock 瀏覽器 創(chuàng)建

標(biāo)簽: , , , , ,