Eclipse运行时定义了插件(所有其他插件都依赖于org.eclipse.osgi和org.eclipse.core.runtime)。
运行时负责定义插件的结构以及插件背后的实现细节(bundle和类加载器)。
运行时还负责查找和执行主要的Eclipse应用程序,并维护插件、它们的扩展和扩展点的注册表。
运行时还提供各种实用工具,如日志记录、调试跟踪选项、适配器、首选项存储和并发基础设施。
当然,作为最小内核,只有在创建了使用它并执行某种任务的插件之后,运行时才会变得有趣。
与Atlas一样,运行时插件坚忍地驻留在插件堆的底部,用它稳定的肩膀高高举起Eclipse宇宙。
目录
Extension points and the registry
The runtime plug-in model
当用户启动用Eclipse开发的应用程序时,将启动平台运行时引擎。
运行时实现平台使用的基本插件模型和基础设施。
它跟踪所有已安装的插件及其提供的功能。
插件是一种结构化的组件,它向系统贡献代码(或文档,或两者兼备),并以结构化的方式对其进行描述。
插件可以定义扩展点,定义良好的功能点,可以由其他插件扩展。
当插件为扩展点提供实现时,我们说它向平台添加了扩展。
这些扩展和扩展点在插件的清单(plugin.xml)文件中声明。
使用公共扩展模型为插件提供了一种结构化的方式来描述它们可以被扩展的方式,并为客户机插件提供了一种结构化的方式来描述它们所提供的扩展。
定义扩展点非常类似于定义任何其他API。
唯一的区别是扩展点是使用XML而不是代码签名声明的。
同样,客户机插件使用XML来描述其对系统的特定扩展。
运行时的一般目标是,终端用户不应该为已安装但未使用的插件支付内存或性能损失。
平台扩展模型的声明性特性允许运行时引擎在不运行插件的情况下确定插件提供了哪些扩展点和扩展。
因此,可以安装许多插件,但是在根据用户的活动请求插件提供的函数之前,不会激活任何插件。
这是提供可伸缩、健壮的平台的一个重要特性。
Plug-ins and bundles
支持插件的机制是使用OSGi框架实现的。
从这个角度来看,插件与OSGi包是一样的。
绑定包及其相关的类指定并实现Java类加载、先决条件管理和绑定包生命周期的过程。
在接下来的讨论中,我们将交替使用术语插件和捆绑包,除非讨论框架中的特定类。
插件
Plugin类表示在平台中运行的插件。
它是一个方便的地方,可以集中插件的生命周期方面和整体语义。
插件可以为其生命周期的启动和停止方面实现专门的功能。
每个生命周期方法都包含一个对BundleContext的引用,它可以提供额外的信息。
生命周期的开始部分值得特别讨论。
我们已经看到,可以从插件的清单文件中获得有关插件的信息,而无需运行插件的任何代码。
通常,工作台中的某些用户操作会导致一系列需要启动插件的事件。
从实现的角度来看,只有在需要加载插件中包含的类时,插件才会启动。
start方法是实现插件初始化和注册行为的方便场所。
但是,重要的是要认识到您的插件可以在许多不同的环境中启动。
像获取一个图标来装饰对象这样简单的事情都可能导致加载插件的一个类,从而启动插件。
过度的初始化会导致插件的代码和数据在必要的时候很久就被加载。
因此,仔细查看插件的初始化任务并考虑在启动时执行初始化的替代方案是很重要的。
- 在插件启动期间,如果能够快速执行注册侦听器或启动后台线程等注册活动,那么它们是合适的。但是,如果注册活动有副作用(如初始化大型数据结构或执行不相关的操作),则建议在访问插件数据时触发这些操作。
- 数据的初始化最好在第一次访问数据时进行,而不是在启动代码中自动进行。这确保了只有在真正需要时才会构建大型数据结构。
包上下文
生命周期管理是OSGi“捆绑”术语和平台的“插件”术语相结合的地方。
当您的插件启动时,会给它一个对BundleContext的引用,它可以从这个引用中获得与插件相关的信息。
BundleContext还可以用来查找系统中的其他bundle /插件。
BundleContext.getBundles()可以用来获取一个包含系统中所有bundle的数组。
可以注册BundleEvent的监听器,这样当另一个bundle的生命周期状态发生变化时,插件就能感知到。
更多信息请参阅javadoc中的BundleContext和BundleEvent。
在3.0之前,提供了一个插件注册表(IPluginRegistry)来提供类似的信息。
例如,可以查询系统中所有插件的插件描述符。
这个注册表现在已经弃用,应该使用BundleContext来实现这个目的。
平台注册中心现在专门用于关于扩展和扩展点的信息。
包激活器
BundleActivator接口定义了在插件中实现的启动和停止行为。
尽管Plugin类是实现这个函数的方便场所,但插件开发人员完全可以在任何适合插件设计的类中实现BundleActivator的接口。
事实上,如果您的插件没有特定的生命周期管理需求,那么它根本不需要实现这个接口。
包
每个插件的下面都有一个由框架管理的OSGi包。
Bundle是模块化的OSGi单元。
从根本上说,包就是安装在平台上的文件(资源和代码)的集合。
每个bundle都有自己的Java类加载器,并包含用于启动、停止和卸载自身的协议。
从Eclipse平台的观点来看,Bundle仅仅是一个实现类。
插件开发人员不扩展bundle类,而是使用Plugin或其他BundleActivator实现来表示插件。
Extension points and the registry
虽然运行时插件和运行时工具可能会对插件的“捆绑”方面感兴趣,但更常见的是,插件关心插件定义了哪些扩展点,以及插件贡献了哪些扩展。
该信息由平台扩展注册表IExtensionRegistry提供。
为什么插件可能想知道有哪些扩展?
一个具体的例子将有助于说明对该信息的需要以及获取该信息的协议。
回想一下workbench Show View对话框,它显示了平台中已安装的所有可用视图。
我们知道,所有提供的视图的类别名称和视图名称都指定在为org.eclipse.ui.views提供扩展的任何插件的plugin.xml文件中。
但是工作台如何找到这些信息呢?
从平台扩展注册表。
下面的代码是一个基于Show View对话框的工作台实现的简化代码片段:
...
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint point = registry.getExtensionPoint("org.eclipse.ui.views");
if (point == null) return;
IExtension[] extensions = point.getExtensions();
for (int i = 0; i < extensions.length; i++)
readExtension(extensions[i]); //get the information about each extension
...
我们在上面看到,注册表可以从Platform类中获得。
IExtensionRegistry中的协议用于查找名为org.eclipse.ui.views的扩展点。
可以使用IExtensionRegistry、IExtensionPoint和IExtension中定义的协议在注册表中找到关于特定扩展点或扩展的信息。
这些类的javadoc提供了关于注册表协议的详细信息。
一旦找到了感兴趣的扩展定义,就可以使用iconfigationelement中的protocol来检查扩展的各个属性。