Eclipse平台学习笔记(1)-Notes on the Eclipse Plug-in Architecture

时间:2023-01-15 13:03:59
Eclipse包含一个插件管理核心,叫做Eclipse平台或Eclipse运行时,一些核心的插件在每一个插件的部署中都会出现。这些核心插件的标识符都被硬编码到Eclipse平台中,平台在运行时自动会加载这些核心插件。对于非核心插件,采用“懒加载”法则,只有在请求时才被加载。

 

Eclipse平台中,插件与其他插件有两种关系:

  • 依赖关系:具有这种关系的插件包括依赖插件和被依赖的插件。被依赖的插件为所依赖的插件提供功能上的支持。
  • 扩展关系:具有这种关系的插件包括宿主插件和扩展插件。一个扩展插件扩展了宿主插件的功能。

这些关系在插件的plugin.xml文件中进行声明。具体对应其中的requiresextension声明。

依赖关系:

plugin文件中定义的依赖关系是运行时和编译时的共同指令。在运行时,Eclipse在依赖插件启动时需要确保被依赖的插件能够得到。在编译时,Eclipse能够根据依赖关系查找被依赖插件的参数和类路径。

扩展关系:

扩展的定义:向插件中添加一些处理元素或一般元素的过程叫做扩展。

任何插件都允许其他插件通过添加处理元素的方式对其进行扩展。扩展会导致宿主插件更改其行为,这种更改包括:向宿主插件中添加处理元素;利用扩展插件提供的服务定制这些额外元素的行为。

最简单的情况下,可以为环境中添加一个单独的回调函数,并通过这种方式使得宿主和扩展插件进行通信。注意回调对象是简单的java对象,由插件提供者的代码进行控制。

需要注意的是,前面的这些方式仅仅是一般的原则,扩展并不一定需要回调函数,宿主函数可以提供某种扩展,the kind of behavior modification required of a host plug-in can be provided entirely by objects whose classes are known to the host plug-in at compile-time, so that an extension declaration serves merely to parameterize instances of such built-in classes.(宿主类在编译时可以知道扩展类???)

一个扩展点允许任意多数量的扩展插入该扩展点。

对扩展关系进行详细讨论:

扩展关系一般由四个角色进行参与:宿主(host),扩展者(extender),一般意义上的回调对象(callback object)和由每个扩展点定义的具体的回调角色(callback roles)。

  1. 宿主:

提供将被扩展的扩展点,除此以外,这样的插件也可以扮演对一系列扩展的协作者和控制器的角色。具体实现时,会在宿主得到plugin文件中声明扩展点xml元素:如下图所示:

Eclipse平台学习笔记(1)-Notes on the Eclipse Plug-in Architecture

图中第一部分定义了宿主插件的基本信息,第二部分定义了该宿主插件的扩展点。扩展点的id与宿主的id共同组成了一个在全局上下文中的唯一标识,对于上图,就是org.eclipse.ui.actionSets;在2中宿主插件还定义了一个schema,用来描述扩展者在扩展该扩展点时需要遵守的语法规则。(这个schema一般在宿主插件源代码主文件夹中的schema文件夹下,后缀名是.exsd,其实就是一个标准的xml schema文件:actionSet.exsd,如下图所示)。

Eclipse平台学习笔记(1)-Notes on the Eclipse Plug-in Architecture

上图表明了actionSet扩展点完整的shema定义,一般情况下,这些属性并不都是必须的。

经过搜索,没有在eclipse平台的执行环境中发现对应的schema文件,只是在pluginsrcp源文件中发现了schema文件夹,不知平台是如何找到这些schema文件并进行验证的???

  1. 扩展者(extender):

定义扩展;通过扩展使得自身的某些方面对于宿主是可使用的;并使得宿主插件添加将某些处理元素添加到其环境中。

Eclipse平台学习笔记(1)-Notes on the Eclipse Plug-in Architecture

扩展者根据schema的定义书写对应的plugin文件,实现对某个扩展点的扩展。

  1. 回调对象

在具体的扩展上下文中,表示回调角色的对象是一般的java对象(plain old java object),不是插件。当某些在扩展点契约中声明的事件发生并被宿主插件识别时,宿主插件会调用回调对象。

具体的回调对象:

每一个回调对象在扩展中填充一个特定的具体角色,这些具体的角色称为回调对象。在plugin文件中,这些回调对象作为一个扩展点的子元素出现。图中的action子元素就是一个回调对象。多个回调对象都可能存在于一个扩展中(本例子是actionSet扩展),每一个回调对象服务于一个具体的workbench菜单项或按钮。当用户需要实现一个回调对象时,对应扩展点的XML Schema通常会包含一个属性,用来指示具体的回调实现类。如

上图中的class=org.eclipse.help.internal.ui.HelpAction。需要注意的是,根据“懒加载”法则,只有当宿主插件执行某些特定的动作时,回调对象才被创建。

关于事件响应:作为对一个扩展者插件的扩展设计者,我们需要了解一个扩展的回调角色,并提供对这些角色的具体回调对象。这些角色在扩展点相关的XML Schema中具体描述,并在XML Schema当一个新的服务通过主工作平台菜单被访问到时,服务的plugin提供了

非具体的服务对象

注意并不是所有用来定义一个扩展点的XML元素都与定制的回调角色对应。有些元素可能是纯描述性的,例如支持宿主插件的某些参数,形成对应的UI元素或者用来创建非定制的内部宿主对象,这些对象可以表示部分扩展。在上面的例子中,一个actionSet元素内部和其自身(独立与其子元素)没有定义定制的回调对象。但是这样的一个元素不会导致一个内部元素存在于org.eclipse.ui插件中,从而表示一个动作集合。

作为一个扩展点的使用者,我们不必考虑那些由宿主插件支持的非具体的内部对象。但是作为一个宿主插件的设计者,我们会发现我们能够灵活地设计复杂的扩展结构,其中一部分通过扩展暴露为回调函数,其他可以是一般的,内建在宿主插件的代码中,可能通过对应扩展的XML属性参数化。

插件和扩展对象的关系:

插件对象,扩展点和回调对象的关系:

  1. 在一个宿主插件可能存在多个扩展点
  2. 一个插件可以作为一个宿主插件,暴露出一些扩展点,同时也可以作为一个扩展的插件扩展一些插件。
  3. 一个给定的扩展点可能被多个插件扩展。
  4. 一个插件可能对一个给定的扩展点扩展多次。
  5. 一个扩展者插件可能包含不同宿主插件的不同扩展。
  6. 由一个具体插件对一个扩展点的一次单独扩展可能会创建多个回调对象。
  7. 一个插件能够定义属于自身扩展点的扩展。

其中对自身扩展明显的例子是ui插件本身,该插件对自身提供的扩展点进行扩展,并添加了许多功能。

扩展点的Schema

宿主插件需要创建扩展点,并在其plugin文件中声明扩展点扩展点的配置语法。这种语法用Schema定义并存储在后缀名为.exsd的文件中,并成为宿主插件的文档之一。

通常来说,一个具体的扩展规范通常(退化??)是一系列的元素,这些元素称为一个扩展成员。例如前面对actionSet的扩展,可能的表示如下:

<extensions point="org.eclispe.ui.actionSet" …>

 actionSet(可能出现一次或多次),这个元素就是后面所说的配置元素(类型是接口IConfigurationElement),在actionSet中可能会有action的零次或多次出现,action元素可以通过IConfigurationElement的方法进行访问。

扩展的具体过程

对特定扩展点扩展的声明处理:总的来说,对一个扩展的配置是任意的,系统中只有宿主插件了解这个配置(宿主插件提供了对扩展点schema的定义)。

为了使宿主插件能够处理其定义扩展点的扩展,它需要具有从Eclipse运行时中获得这些扩展列表的能力,对于每一个扩展,都需要得到扩展成员解析后的结构。这些功能是由plugin注册API提供的,这些API提供了遍历插件,插件的组件和插件之间关系等信息。在注册API中的配置元素(接口IConfigurationElement)表示扩展者plugin文件中扩展元素解析后的结构。

Eclipse平台学习笔记(1)-Notes on the Eclipse Plug-in Architecture

首先得到平台的插件注册项IPluginRegistry,然后通过扩展点的id得到对应的扩展点,再遍历该扩展点下的所有扩展,对于每一个扩展,解析对应的plugin文件(??),得到对应的扩展元素集合(plugin文件中的扩展),遍历所有的扩展元素,得到IConfigurationElement类型的实例,调用对应的方法就可以将菜单项,按钮等配置到workbench用户接口中,并在需要的时候调用合适的回调对象。

可以使用IExtensionPoint中的方法直接得到所有扩展的元素(IConfigurationElement类型),可以简化步骤。

标准化的扩展处理过程:

基本原则:懒加载原则,只有当回调对象需要做实际工作时才进行实例化和初始化工作。

 持续。。。