大多数Java™编程语言开发人员通过其作为IDE的功能被引入Eclipse。 Eclipse IDE实际上由称为插件的交互组件的集合组成。 这些构成IDE基础的插件也可以用于创建其他桌面应用程序。 创建基于Eclipse的应用程序所需的最少插件集称为Eclipse Rich Client Platform (RCP)。 但是,插件不仅会自己启动。 它们需要启动和运行的环境。 Eclipse为该环境提供了OSGi R4规范的实现。
因为Eclipse是OSGi驱动的核心,所以了解Eclipse插件的概念与OSGi框架之间的关系非常重要。 在本文中,我将通过描述Eclipse平台上的插件来详细解释这种关系。 然后,我将通过今天基于OSGi的实现来描述Eclipse V2.1平台中插件的演变。 最后,将详细介绍适用于Eclipse插件的OSGi提供的manifest.mf选项。
什么是插件?
Eclipse联机帮助定义了一个插件,如下所示:
“插件是对系统起作用的代码和/或数据的结构化捆绑。可以以代码库(带有公共[应用程序接口] API的Java类),平台扩展甚至文档的形式来贡献功能。插件可以定义扩展点,定义明确的位置是其他插件可以添加功能的地方。”
重点关注的是插件以结构化的方式发挥作用。 它们可以提供诸如日志记录之类的服务,或者诸如编辑器之类的用户界面(UI)中可用的片段功能。 无论其功能如何,所有插件都以相同的结构化方式定义。
向OSGi的演变
如前所述,Eclipse使用OSGi作为其插件系统的基础。 但是,情况并非总是如此。 Eclipse的早期版本也被设计为插件的集合,并且Eclipse包括了自己的专有插件系统来管理交互。 但是,随着Eclipse IDE需求的增长,很明显,需要更强大的解决方案。 这个新系统的基本要求包括能够动态处理新插件的添加和停止现有插件的能力。 经过大量研究,Eclipse创建者决定通过实现OSGi框架规范来替换专有的插件框架。
OSGi是服务平台的规范。 Eclipse提供了此规范的许多可用实现之一,并用作最新OSGi R4规范的参考实现。 OSGi是基于Java的框架,旨在供需要较长运行时间,动态更新以及对运行环境造成的干扰最小的系统使用。 最初,OSGi的目标是家庭自动化和住宅网关设备。 最近,它已发现从手机到汽车的各种用途。
OSGi的核心是组件和服务模型。 OSGi规范定义了称为bundle的模块化单元。 (除非本文其余部分明确指出,否则Eclipse术语插件和OSGi术语捆绑包可以互换使用,因为所有Eclipse插件现在都是OSGi捆绑包。)OSGi还提供Java虚拟机(JVM)级别的服务捆绑软件可用于发布,发现和绑定服务的注册表。
OSGi规范定义了捆绑软件生命周期以及捆绑软件如何交互的基础架构。 这些规则是通过使用特殊的Java类加载器来强制执行的。 在普通的Java应用程序中,CLASSPATH中的所有类对于所有其他类都是可见的。 相比之下,OSGi类加载器基于OSGi规范和manifest.mf文件中为每个捆绑包指定的选项(在本文稍后详细介绍)来限制捆绑包之间的类交互。
Eclipse IDE使用OSGi的一个子集,该子集围绕模块化和捆绑软件生命周期进行。 但是,它很少使用OSGi提供的服务支持。 取而代之的是,Eclipse提供了自己的扩展点系统来实现包交互。 捆绑包将功能公开为对其他扩展的贡献。 捆绑包还定义了自己的扩展点,其他捆绑包可能会贡献这些扩展点。 在Eclipse中使用扩展点的一个示例是Preferences窗口。 核心Eclipse插件提供了中央窗口,并公开了扩展点以允许添加其他首选项页面。 在将新插件添加到Eclipse时,它们可以贡献自己的页面。 Eclipse中的扩展点模型与基本的OSGi服务不同。 捆绑包扩展点归定义捆绑包所有; 其他捆绑只是对它们的贡献。 相比之下,任何捆绑软件都可以实现和使用OSGi服务。
使用OSGi实现Eclipse
在3.1之前的Eclipse版本中,您在每个插件的plugin.xml文件中定义了插件依赖性以及扩展和扩展点。 在使用OSGi的较新版本的Eclipse中,依赖项信息已分解成manifest.mf文件,而plugin.xml文件仅包含扩展名和扩展点的XML定义。 来看一下这种演变的实时实例,这很有用。 清单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="*"/>
声明公开了该插件中的所有软件包,以供其他插件使用。 插件依赖项导入部分列出了org.eclipse.pde.ui插件所需的必备插件。
接下来的两节定义了扩展点org.eclipse.pde.ui可用于其他插件,以及它们对它们的贡献。 在这种情况下,您可以看到自定义Eclipse插件开发环境(PDE)透视图的定义。
让我们看一下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>
请注意,导出和导入信息已消失。 现在,此信息位于清单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
现在,将各种插件导入指定为必需的包,并且*包导出已替换为显式导出的包列表。
当Eclipse宣布这一消息时,从插件级依赖关系转变为需要显式导出和导入软件包的依赖关系引起了很大的反响。 主要的抱怨是缺少等效的<export name="*"/>
,这在早期的Eclipse版本中已经存在。 但是,有很多原因会导致这种遗漏。 最重要的原因是显式导入和导出可提高速度。 早期版本的Eclipse必须打开并扫描每个插件jar文件,以确定它包含哪些类。 不包括*导出还可以提供一定程度的保护,以防止插件暴露不需要的类。 插件开发人员必须做出明智的选择,以使插件中的功能可供外部使用。 此限制允许内部程序包保持内部状态。
OSGi清单选项
OSGi R4框架核心的当前规范草案几乎为300页PDF格式。 涵盖本规范的每个部分都不在本文的讨论范围之内,但是我确实讨论了Eclipse插件开发人员特别感兴趣的OSGi manifest.mf选项:
-
此类用于启动和停止捆绑包。
在上面的示例插件中,指定了
org.eclipse.pde.internal.ui.PDEPlugin
类。 此类扩展了org.eclipse.core.runtime.Plugin
,该实现了BundleActivator
接口。
Bundle-Activator
-
此属性指定用于捆绑软件的CLASSPATH。
该属性可能包含对捆绑jar文件中目录或jar文件的引用。
您可以使用句点来指示捆绑软件的根。
对于示例Eclipse PDE捆绑包,在捆绑包jar文件中指定了org.eclipse.pde.ui_3.1.0.jar。
如果您将插件的源版本导入到工作空间中,则导入过程会将捆绑软件的CLASSPATH更改为
Bundle-ClassPath:
这将允许插件的开发版本选择已编译的捆绑软件类。
Bundle-ClassPath
- 此属性指定捆绑软件的版本号。 软件包导入和必需的软件包规格可能包括软件包的版本号。
Bundle-Version
- 此属性指定所有要公开公开给其他插件的软件包。
Export-Package
- 此属性指定要从所需插件中显式导入的所有软件包。 默认情况下,必须解析所有软件包才能启动捆绑包。 您还可以将软件包导入指定为可选,以支持其中可能不存在软件包的情况。 显式导入的类在Require-Bundle插件中的软件包之前被解析。
Import-Package
- 此属性指定要导入的捆绑软件及其导出的软件包,以在给定的捆绑软件中使用。 指定的包在显式包导入后进行评估。
Require-Bundle
Eclipse提供的其他清单选项
OSGi规范包括的manifest.mf配置选项不能提供Eclipse平台所需的所有功能。 结果,Eclipse创建者添加了一些扩展(并提出了将其包含在OSGi规范的未来版本中的建议):
-
Eclipse有两种
osgi.resolver
属性可以指定的OSGi解析器方法(default
和strict
。 Eclipse还包括对Export-Package
属性的两个扩展x-internal
和x-friends
friends-启用严格模式时都将强制执行这两个扩展。
Export-Package
标题扩展
- 此属性的默认值为false 。 使用此选项将内部软件包指定为true时 ,Eclipse PDE会阻止其使用。
x-internal
-
此选项类似于
x-internal
,但是允许某些捆绑包使用具有此选项的导出软件包。 不鼓励其他捆绑销售。x-internal
选项优先于x-friends
。
x-friends
- 默认情况下,Eclipse按需加载捆绑软件。 因此,当导入捆绑软件的捆绑软件要求包含捆绑软件的第一类时,便会加载捆绑软件。 将此值指定为?? 使Eclipse在启动时加载捆绑软件。 您还可以指定例外列表,这些例外是类和资源,并且可以在不启动其包含包的情况下加载它们。
Eclipse-AutoStart
-
使用此属性,可以指定要启动捆绑包必须评估为true的条件。
您可以在指定的表达式中包含以下信息:
-
osgi.nl
语言 -
osgi.os
用于操作系统 -
osgi.arch
用于建筑 -
osgi.ws
用于窗口系统
SWT_AWT
桥的插件之前验证操作系统是否不是Mac OSX。 (标准Widget Toolkit(SWT)的Mac OS X实现当前不支持此功能。) -
Eclipse-PlatformFilter
- 此选项指定捆绑软件的类加载策略。 通常,捆绑包仅在其内部类和从相关捆绑包导入的类中具有可见性。 Hibernate是Eclipse新闻组中用来解释伙伴类加载的流行示例。 Hibernate框架必须查看用户创建的类和资源,这些类和资源不属于Hibernate本身。 一种情况是使用项目从Hibernate Query Language(HQL)查询动态填充类时。 默认情况下,Hibernate将无法在包含Hibernate jar文件的插件之外看到类,并且需要修改Hibernate插件以创建每个包含Hibernate映射的类的插件。 幸运的是,您可以使用Buddy类装入器选项部分中介绍的伙伴类装入器选项来解决此问题。
Eclipse-BuddyPolicy
Eclipse和OSGi的未来方向
Eclipse在OSGi的使用中受益匪浅,获得了以动态方式管理组件生命周期的强大系统。 每天都在探索新用途,例如服务器层上具有servlet,JavaServer Pages和Eclipse风格插件中的其他HTTP资源的动态Web存档(WAR)文件。
Eclipse基金会已将自身定位为在推动OSGi规范向前发展中发挥关键作用,无论是其自身用途还是其他利用OSGi的各方。 从适当的Eclipse插件框架过渡到OSGi的过程中,对OSGi规范进行了许多添加,成为OSGi R4规范版本的一部分。 因此,Eclipse Equinox项目已成为前进的OSGi参考实现。 这种参与以及创建Java规范请求(JSR)291来管理演进OSGi,保证了Eclipse / OSGi合作伙伴关系将在未来几年中继续取得成功。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-ecl-osgi/index.html