大多数 Java™ 编程语言开发人员通过作为 IDE 的功能认识了 Eclipse。Eclipse IDE 实际上由叫做插件 的交互式组件的集合组成。这些插件组成了 IDE 的基础,它们还可用于创建其他桌面应用程序。创建基于 Eclipse 的应用程序所需的最小插件集称为 Eclipse Rich Client Platform(RCP)。但是,插件本身不能启动。它们需要在一个环境中启动和操作。Eclipse 使用 OSGi R4 规范的实现提供了该环境。
因为 Eclipse 在本质上是由 OSGi 驱动的,因此必须了解 Eclipse 插件的概念与 OSGi
框架有什么关系。在本文中,我将通过描述对 Eclipse 平台而言插件是什么来详细解释这种关系。然后,将描述在 Eclipse V2.1
平台到今天基于 OSGi 的实现中插件的发展。最后,将详细介绍应用于 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 是一个组件和服务模型,如图 1 所示。OSGi 规范定义了一个叫做绑定包 的模块化单位。(在下文中,除非特别指明,Eclipse 术语插件 和 OSGi 术语绑定包 可交换使用,因为所有 Eclipse 插件现在都是 OSGi 绑定包。)OSGi 还提供了 Java Virtual Machine(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 Plug-in Development Environment(PDE)视图的定义。
下面来看 Eclipse V3.1 中的同一插件定义。
清单 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>