Eclipse插件体系结构

“插件是为系统提供功能的代码和/或数据的结构化包。可以以代码库(带有公共[应用程序接口] API 的 Java 类)、平台扩展甚至文档的形式来提供功能。插件可以定义扩展点、定义良好的位置,其他插件可以在这些位置添加功能。”

Eclipse使用OSGi作为插件系统的基础。动态添加新插件和停止现有插件的能力。以动态方式管理组件生命周期的一个健壮的系统。

OSGi是基于Java的框架,旨在用于需要长运行时间、动态更新和对运行环境破坏最小的系统。

OSGi规范定义了绑定包生命周期的基础架构和绑定包的交互方式。这些规则通过使用特殊 Java类加载器来强制执行。

在一般Java应用程序中,CLASSPATH中的所有类都对所有其他类可见。相反,OSGi类加载器基于OSGi规范和每个绑定包的manifest.mf文件中指定的选项来限制类交互。

在3.1之前版本的Eclipse中,在每个插件的plugin.xml文件中定义插件依赖关系以及扩展和扩展点。在使用OSGi的新版本Eclipse中,依赖关系信息被分解到manifest.mf文件中,而 plugin.xml文件只包含扩展和扩展点的XML定义。

插件级的依赖关系改为需要显式导出和导入包的依赖关系。插件开发人员必须进行专门选择来使插件中的功能可供外部使用。该限制允许内部包保留在内部,避免插件暴露不必要的类。

Eclipse的扩展和扩展点 可插拔

每一个希望被别的模块扩展的模块,都必须声明一系列的扩展点,即插座;希望在这个模块上扩展功能的模块,需要按照扩展点的什么来编写扩展,即插头。扩展点提供服务,扩展是要服务。

延迟装载,只有在一个插件被其他模块调用的时候,才装载到内存中。

通过将扩展的声明和实现分离,eclipse实现类延迟装载。

扩展点和扩展的声明都是通过XML文件完成的,即清单文件MANIFEST.MF,描述了一个插件能够做什么,而JAVA代码则具体完成这些功能。系统启动时,只需搜索清单文件,建立一张索引表,知道有哪些插件以及能够提供什么服务。当eclipse第一次启动时,eclipse运行时会遍历plugins文件夹中的目录,扫描每个插件的清单文件信息,并建立一个内部模型来记录它所找到的每个插件的信息。

RCP包括基于OSGi的运行时框架Equniox,基于SWT/JFace的图形模块,eclipse平台的UI和Runtime模块。基于Eclipse的应用程序所需的最小插件集称为Eclipse Rich Client Platform(RCP)

Eclipse插件体系结构_第1张图片

Platform Runtime 平台运行库是内核,它在启动时检查已安装了哪些插件,并创建关于它们的注册表信息。即在eclipse运行时发现和管理插件。为降低启动时间和资源使用,它在实际需要任何插件时才加载该插件。除了内核外,其他每样东西都是作为插件来实现的。

Workspace 工作区是负责管理用户资源的插件。这包括用户创建的项目、那些项目中的文件,以及文件变更和其他资源。工作区还负责通知其他插件关于资源变更的信息,比如文件创建、删除或更改。

Workbench 工作台为Eclipse提供用户界面。它是使用标准窗口工具包(SWT)和一个更高级的 API(JFace)来构建的;SWT 是 Java 的 Swing/AWT GUI API 的非标准替代者,JFace 则建立在 SWT 基础上,提供用户界面组件。

插件可以扮演双重角色,其他插件服务的使用者和其他插件服务的提供者。

 

manifest.mf

Bundle-Activator

该类用于启动和停止绑定包。该类扩展 org.eclipse.core.runtime.Plugin,实现了BundleActivator 接口。

Bundle-Version

该属性指定绑定包的版本号。包导入和必需的绑定包规范可以包括绑定包版本号。

Export-Package

该属性指定要公共暴露给其他插件的所有包。

Import-Package

该属性指定要从必需插件中显式导入的所有包。默认情况下,必须为要启动的绑定包解析所有包。还可以将包导入指定为可选项,以支持包不存在的情况。显式导入的类在 Require-Bundle 插件中的包之前解析。

Require-Bundle

该属性指定要在给定绑定包中导入使用的绑定包及其已导出的包。指定的绑定包在显式包导入之后解析。

 

 

----------------------            -------------------- 
|plugin A            |            |plugin B          | 
|   ---------------  | contibute  |  --------------  | 
|   | ext point p | <--------------- | extension  |  | 
|   ---------------  |_           |  --------------  | 
|         ||         | |          |        ||        | 
|   ---------------  | |implement |  --------------  | 
|   | interface I | <--|------------ | class  C   |  | 
|   ---------------  | |          |  --------------  | 
---------------------- |          ----------/ ------- 
                       |  create, call       | 
                       ----------------------|

你可以把extension point想为接口, 而我们扩展这些extension,其实就是实现了这个接口

假设plugin A定义了一个extension point,  plugin B定义了一个extension,是基于plugin A的这个extension point的,它的实现类是class C,那eclipse启动后, 会读取每个plugin的配置plugin.xml,然后发现plugin B有一个基于ext point p的扩展,那它就会用interface I作为对象, 然后实例化一个class C, 就等于实现了这个extension

 

eclipse的内部实现
IPluginRegistry registry = Platform.getPluginRegistry(); 
IExtensionPoint extensionPoint = registry.getExtensionPoint(xpid); //通过扩展点ID获得扩展点
IExtension[] extensions = extensionPoint.getExtensions(); //获得该扩展点的所有扩展
// For each extension ... 
for (int i = 0; i < extensions.length; i++) { 
    IExtension extension = extensions[i]; 
    IConfigurationElement[] elements = extension.getConfigurationElements(); //获得扩展点配置元素
    configurationElement[j].createExecutableExtension(“Class”); //为每个回调对象创建实例

    ……

eclipse就是注册每一个extension和extension point,然后用extension point来实例化它对应的那个extension。

发生事件并向其它对象请求处理的对象被称为“事件对象”,而处理事件的对象被称为“回调对象”。回调对象由扩展者插件定义,由宿主插件创建实例。

Eclipse bundle 使用各自的 class loader ,若需要引用其他 bundle 类来动态创建实例,则需要使用类所在的 bundle class loader

你可能感兴趣的:(eclipse插件)