1.Eclipse平台体系结构
1)Eclipse平台架构
Eclipse是围绕插件概念构建的,Eclipse平台部分的所有子系统除了很小的核心之外,都是由插件构成。 Eclipse平台中的每一个子系统本身是由实现某些关键功能的一组插件构建的。这些插件的包括内容如下:
--“Platform Runtime”(平台运行库,Runtime+Equinox)是Eclipse平台的核心,它是一个微内核,是插件的核心引擎,负责管理插件注册表和插件。它位于平台核心中最低级别的部分,由org.eclipse.osgi和org.eclipse.core.runtime两个插件组成,其他所有的插件都依赖于这两个插件
--“Workspace”(工作空间)是负责管理用户资源的插件。用户资源包括用户创建的项目和项目中的文件等。Workspace相当于Model-View-Controller结构中的Model。
--“Workbench”(工作台)插件为Eclipse提供用户界面。它为添加用户界面(UI)组件(例如视图、菜单)定义了扩展点(ExtensionPoints),同时也提供了附加工具集(SWT和JFace)用于建造用户界面。工作台是在JFace/SWT和平台运行库的基础上构建的。Workbench相当于Model-View-Controller结构中的View。
--“SWT(StandardWidgetToolkit,标准小窗口工具箱)”是Eclipse自己的图形API包,
--“JFace”是使用SWT实现的一个用户界面工具包,用于处理常见的用户界面编程任务,使工具开发者专注于实现插件的功能,而不必在界面设计上花过多的精力。
--小组(Team),Team插件为Eclipse中集成各种类型的源码控制管理系统(如,CVS等)提供服务;
--Help,该插件为开发者编写帮助文档提供支持;
运行时和工作空间组成了Eclipse的核心部分。通常所说的Eclipse插件便是向基于Eclipse核心的系统提供服务的组件。在Eclipse SDK中,除了Eclipse平台以外,还包括Java开发工具(JDT)和插件开发环境(PDE)两个组件来支持插件开发。
--JDT,JDT提供了Java程序的编辑、编译、调试、测试功能,实现功能完整的Java开发环境;(在Eclipse平台之上也可以使用其他的开发工包,如CDT等)
--PDE,PDE为插件开发环境提供了支持,提供了自动构建、处理、调试、和部署插件的工具;
Eclipse平台和JDT,PDE构成了Eclipse的三层结构。在三层架构之上,用户可以遵循Eclipse平台定义的插件结构自行编写插件来扩展Eclipse平台的功能。
其中,工作台层次结构:
Eclipse工作台(Workbench)是不可见的,它包括一个或多个Eclipse工作台窗口(WorkbenchWindow)。每个工作台窗口又包含菜单栏,工具栏和多个工作页面(IWorkbenchPage)。主要的工作台部件--View和Editor就包含在工作台页面中。
2)插件工作模式
Eclipse将各个模块分离成了离散的的功能部件,那么,各个插件是以什么样的模式工作的呢?
Eclipse通过插件依赖的关系将不同的插件联系在一起。每一个插件可以依赖其他插件也可以被其他插件依赖。Eclipse的这种工作模式为开发者提供了开放的工作环境,有助于快速开发出功能强大的应用程序。
插件模式是一个扩展体系,随着规模的越来越多,Eclipse运行时所消耗的资源会迅速增长,直到资源消耗殆尽,为了避免这种情况,Eclipse使用了懒加载的工作方式,这样,就可以安装较多的插件,但不会在启动的时候就激活它们,直到用户的活动请求了该插件所提供的功能为止。
2.插件的加载过程
Eclipse启动时,平台运行库需要完成两个简单的动作:
1)定位JRE的位置,然后调用org.eclipse.equinox.launcher.Main启动,扫描plugins和features目录下的插件配置文件,对插件进行初始化注册到OSGi中,并保存配置文件中的信息;
2)查找清单文件中声明的extensionpoint和extension,并将二者匹配以保存插件的依赖关系。最后启动应用Application。运行时对插件实行“lazy load”机制,只有当需要使用插件时才开始调用插件中的start()方法将其调入内存,不需要时选择适当的时机清除出内存。
3.插件信息的获取
每个捆绑插件都有一个象征性标识符(symbolicName),在MANIFEST.MF文件中,形如:
Bundle-SymbolicName: org.xxxx.builder.ui;singleton:=true
这个象征标识符便是插件的唯一标识。不论插件有没有启动,都能使用
Platform.getBundle(symbolicName)来获得捆绑软件对象(org.osgi.framework.Bundle)。当插件启动后,插件的信息由内存中的捆绑软件上下文管理。如果安装了兼容插件(3.0以前的),使当前Eclipse版本同先前版本兼容,便可以使用原来的Platform.getPlugin(pluginID)来获得插(org.eclipse.core.runtime.Plugin)。
一些常用的获得插件信息的方法:
bundle.getEntry(“/”);----获得插件的安装目录的URL
bundle.getSymbolicName()-----返回插件的唯一标识。
Platform.getResourceBundle(bundle)---返回当前区域对应的插件资源包对象
(java.util.ResourceBundle)。这个包对象中的信息会在插件发布后,作为插件安装目录中的plugin.properties文件而存储。如果要验证插件是否被激活,则需要检查bundle的状态,代码为:bundle.getState==org.osgi.framework.bundle.active
-Eclipse平台会在启动的时候读入所有的清单文件,因而启动Eclipse之后,所有需要使用的扩展点都会记录在内存中。Eclipse使用插件注册表来管理插件的所有扩展点和扩展信息,因而可以使用如下的方法来获取扩展点:
IExtensionRegistry.getExtensionPoint("org.eclipse.uiactionSet");
并通过IExtensionRegistry、IExtensionPoint和IExtension等接口访问其中储存的信息。
--要获得全部的扩展对象:extensionPoint.getExtensions();该方法返回记录所有扩展(IExtension对象)的数组。
--获得配置元素:Extensions[i].getConfigurationsElements();
--创建回调对象:configurationElements[j].createExecutableExtension("class");
IExtensionRegistry registry=Platform.getExtensionRegistry();//得到扩展注册表
IExtensionPoint point=registry.getExtensionPoint("org.test.xx");//通过扩展点Id查找扩展点
IExtension[] extensions=point.getExtensions();//得到扩展自该扩展点的所有扩展
IExtension extension=registry.getExtension("myextensionId");//通过扩展Id获得扩展
4.插件的扩展模式
宿主插件(host plug-in):提供扩展点的插件;
扩展插件(extender plug-in):使用扩展点的插件;
回调对象(call-back object):实现宿主和扩展插件之间的通信;
扩展的加载过程:
1)从Eclipse平台取得扩展点;
2)取得已在此扩展点上注册的扩展;
3)取出以XML方式声明的配置元素;
4)根据每个配置元素的属性值创建回调函数;
5)处理创建的对象;
======================================================================
5.自定义扩展点
一个扩展点的定义由两个部分组成:plugin.xml文件中扩展点的声明;扩展点Schema文件(Schema文件的路径会在声明中指定),schema指定一个扩展名是exsd(Eclipse XML Schema Description)的文件,它对实现这个扩展点的扩展的格式做了定义。
------------------------------------------
Eclipse平台中的扩展点设计实例
Eclipse繁多的扩展点,总结起来主要有如下几种类型:
1)框架-组件型
主插件提供了某种框架类的实现,而扩展的插件将作为框架中的某一个组件出现。这时,扩展点通常会要求扩展实现某个接口或继承某个抽象类,框架会通过接口或抽象类的方法访问该组件。
Eclipse中和UI相关的扩展点有很多是以这种形式出现的,如org.eclipse.ui插件中的views和editors等。平台为这些GUI组件在窗口中提供显示的位置,通过一个接口类(views对应的IViewPart,editors对应的IEditorPart)访问这些组件,并负责创建、销毁及重新定位它们,这些组件则负责绘制自己窗口内部的内容并进行业务逻辑的处理。另外,如果某个插件声明了一个接口,并要求其他插件提供一个实现,也可以使用这种模式。
也有的情况下,扩展的插件不需要提供一个接口的实现,这种情况下一般是由于该组件已经有了默认的实现类,扩展只需要提供一些配置信息就可以了。如使用org.eclipse.ui.menus扩展点时,用户需要配置菜单ID、名称等信息,插件会自动创建对应的MenuManager对象来处理。
2)集合-元素型
主插件需要处理多种类型的数据,而每一个扩展的插件则提供对一种具体数据的处理逻辑。这种类型的扩展点只要求扩展提供一个名称,也可以要求其通过接口提供处理程序。属于这种类型的扩展点有:org.eclipse.ui.encodings和org.eclipse.core.runtime.contentTypes等。
3) 用扩展点代替代码
这一类型的扩展点所提供的功能,通常既可以通过配置扩展,又可以通过使用API直接编写代码完成。如org.eclipse.ui中的actionSets中的menu部分就是这一类,在为RCP程序配置菜单项时,开发者既可以通过使用扩展点生成菜单,也可以通过新建一个MenuManager对象创建菜单,两者效果完全相同,但在这种情况下,一般推荐通过扩展来配置功能,这可以使程序结构化比较清晰,易于维护和修改,即使做了改动,也不需要每次都重新编译插件代码。
4)提供资源
这种类型的扩展点声明一组资源(如图片、网页文件、文字等)。扩展它的插件提供这些资源内容,拥有扩展点的插件会负责在适当的时候读取并显示它们。
属于这种类型的扩展点有org.eclipse.core.runtime.products和org.eclipse.help.toc等。其中org.eclipse.core.runtime.products用来声明一个产品配置,产品配置主要用在RCP程序中,它包含了一系列被称为“装饰”的图标和为,使用产品配置可以设置程序名称(显示在程序窗口标题栏的文字)、程序图标、about对话框中的图片和文字等。
org.eclipse.help.toc则用于Eclipse的帮助系统中添加自定义内容,Eclipse的帮助系统,由基于XML描述的树形结构(Table Of Content,TOC)和XHTML文件两部分组成,使用toc扩展点,可以将自定义的toc文件和XHEML文件添加到Eclipse的帮助系统中,以为自己的插件创建帮助文档和目录。
plugin.xml的文件片段,供参考:
<extension
point="org.eclipse.help.toc">
<toc
file="toc.xml">
</toc>
<toc
file="testToc.xml"
primary="true">
</toc>
</extension>
---------------------------------------------
创建扩展点
1)打开plugin.xml文件,找到Extension Points选项卡,点击Add按钮,弹出新建扩展点对话框,输入Extension Point ID/Name及Schema文件路径
2)点击finish按钮,平台会自定生成schema文件并在编辑器中打开。Schema的编辑器有三个选项卡:Overview,包含了一些扩展点的描述、版权等扩展点的元信息,这些都是描述性内容对扩展点没影响;Definition,可以以图形化的方式编辑Schema;Source,是schema文件的树状储存结构(xml格式的文本)
3)打开Definition选项卡,可以看到自动生成的extension根元素(与其他元素的不同是,它的格式已定不可更改,如不能新增加属性等),然后开始构建自己的扩展点,首先New Element,新建一个自定义元素并命名。可以为元素的属性指定各种限制,包括类型(boolean,string,java等)。
4)创建了合适的元素及元素的属性后,最后一步就是将它们的引用关联到extension根元素上,更加XSD的规范,首先创建引用容器(choice或sequence),然后需要在其中添加对其他非根元素的引用。
5)自定义扩展点已经建立完毕,它和Eclipse平台提供的扩展点的使用方式一样。
6)最后一步工作就是在提供扩展点的插件中编写调用扩展的代码:
(以下代码上面提到过,这里再列一下)
IExtensionRegistry registry=Platform.getExtensionRegistry();//得到扩展注册表
IExtensionPoint point=registry.getExtensionPoint("org.test.xx");//通过扩展点Id查找扩展点
IExtension[] extensions=point.getExtensions();//得到扩展自该扩展点的所有扩展
IExtension extension=registry.getExtension("myextensionId");//通过扩展Id获得扩展
一个IExtension对象就代表一个扩展。而扩展中声明的作为extension子元素出现的那些元素被称为配置元素(Configuration Element),通过接口IConfigurationElement可以访问它们,用IExtension.getConfigurationElements可以得到某个扩展中所包含的所有子元素,调用getName方法可以获得配置的名称,getChildren方法可以得到该配置所有的子元素集合。
... ...
IConfigurationElement ce=extension.getConfigurationElements()[0];
ce.getName();
ce.getAttribute("Id")
Object obj=ce.createExecutableExtension("class");
... ...
--------------------------------------------------------------------
使用功能部件(feature--特征,特点)
使用功能部件可以实现以下功能:
-声明使用软件产品的前提需求(需要预安装的其他插件或功能部件)
-用户可以禁用整个软件产品(禁用后,相应的插件不会被启动)
-在用户安装了产品后,显示欢迎页面
-在Eclipse平台中显示代表软件产品的标签
-当产品有更新版本时,通过自动升级功能下载安装更新并升级
一个功能部件主要由以下几个部分构成:
-描述:包括对插件的描述,版权声明和许可协议等
-内容:一个功能插件可以保护插件,也可以包含其他功能部件
-依赖性:这部分内容描述了该功能部件所依赖的其他插件和功能部件
-安装:可以指定安装功能部件时的特殊需求(功能部件是否要和别得到功能部件安装在同一个目录下,安装功能部件时调用其他处理程序等)
(1)创建功能部件:new-->Project-->Plug-in Development/Feature Project
-->生成feature.xml,关键的两个标签:Plug-ins,选择其包含的插件;Included Features,选择其包含的其他feature.
(2)创建更新站点:new-->Project-->Plug-in Development/UpdateSite Project
--->生成site.xml,在Site Map中创建Category并添加上面定义的Feature--》在Archives标签中设置更新站点的URL
(该URL和在上面定义的feature.xml中设置的Update Site URL一致)---》在Site Map中点击Build All,生成对应的插件和Feature文件
(3)Eclipse的Help--》Install new software--》Available Software Sites--》Add,添加site.xml所在的目录,然后next。。
--------------------------------------------------------------------