此文档是总结性文档,较宽泛,适合对Eclipse 插件开发有一定了解的同事查阅。
始终忙于插件开发,对eclipse 得本质并未深入研究,在这段时间的studio 技术总结期间,梳理代码时,对已底层的机制认识不清,借此机会深入研究了一下。
在网上google 了下,对OSGI 的定义如下:
OSGi 是什么,OSGi 是一种服务运行平台。通过实现能够提供服务的符合OSGi 规范的组件,用户可以将其组件发布到OSGi 运行平台,供用户和其他组件使用。OSGi 组件提供的服务具有两个层面的含义:系统层面,即一个组件为其他组件提供服务,这些服务体现为Java 接口的实现;业务层面,即一个组件为外部系统或用户提供某种业务服务实现。
这种解释比较抽象不太好理解,我总结下了粗浅得概念以及好处:
OSGi 可以控制访问范围,这方面Java 本身控制得不够细,比如我某个类只希望供某些指定的类使用,Java 是无法做到的(Proptected 只能供同包和子类用)。一句话:osgi 其实就是个classloader (刘成帮语)。
拿J2EE 来说,一个web 应用通常只由一个project 来完成,所有得实现均在此project 中完成,web 应用发布后,若以后新增功能,那么只能在此工程下添加包、类等等,然后再编译打包发布。
而OSGI 框架是由多个project 组成,此project 被OSGI 命名为Bundle (包),每个bundle 有具体的服务或者功能,如果想增加一个全新的功能,那么你只需再开发一个bundle 并部署上就可以了(OSGI 支持热插拔),Eclipse 的插件化概念就是基于OSGI 的理念。
OSGI 理念,我认为是未来的一个方向,把软件开发转向模块块开发(构件化)的方向,同时这也是一种软件设计理念,OSGI 告诉我们,写软件的时候要把职责划分清楚,这是合理划分接口、类、包甚至是服务,组件的基础。以R1Studio 为例,我们在软件设计划分时从大块上划分为Platform ,以及各产品插件。Platform 是运行得基础,主要包括运行的核心包,例如core 包,model 包,ui 包等等。各产品插件包依赖于platform ,各个bundle 各司其职,职责清楚,如果想修改DE-I 的业务,那么只需到DE-I 的bundle 去修改。如果在底层新增个通用的功能,例如调用消息格式,那么只需在platform 里修改,其他产品插件就获得了这个调用功能。若新增了XX 产品插件,就需要再创建一个bundle 。
Eclipse 与OSGI 的关系以及实现
Eclipse 插件开发在OSGI 的显现表现方式是,每个插件(bundle )里有个META-INF\MANIFEST.MF 文件,此文件的定义是符合OSGI 规范的,以com.icss.ro.studio.xprocess 为例,打开MANIFEST.MF ,节选一个片段,如下所示:
Manifest-Version : 1.0
Bundle-ManifestVersion : 2
Bundle-Name : R1 DE-Integration Designer
Bundle-SymbolicName : com.icss.ro.studio.xprocess; singleton :=true
Bundle-Version : 4.1.0
Bundle-Activator : com.icss.ro.studio.xprocess.DeDesignPlugin
Bundle-Vendor : ChinaSoft International
Bundle-Localization : plugin
Require-Bundle : org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.views,
org.eclipse.ui.ide,
org.eclipse.gef,
org.eclipse.ui.workbench.texteditor,
org.eclipse.debug.core,
org.eclipse.ui.forms,
com.icss.ro.studio.core,
com.icss.ro.eclipse.ui,
com.icss.ro.studio.debug,
com.icss.ro.studio.flowcore,
com.icss.ro.studio.model,
com.icss.ro.studio.schema,
....
Eclipse-LazyStart : true
....
Bundle-ClassPath : lib/freemarker.jar,
lib/rodebase3.5.5.jar,
lib/ant.jar,
lib/rodebase4.0.5.jar,
lib/deCommonCode4.0.8.jar,
.
Import-Package : com.icss.ro.gr,
com.icss.ro.gr.client,
....
Export-Package : com.icss.ro.studio.schema.wsdl.parse,
com.icss.ro.studio.schema.wsdl.parse.bean,
com.icss.ro.studio.schema.wsdl.parse.exception,
com.icss.ro.studio.schema.wsdl.parse.handle,
....
通过上例可以看到分为几个部分:
1 ,基础描述部分
Bundle-ManifestVersion : 2
Bundle-Name : R1 DE-Integration Designer
Bundle-SymbolicName : com.icss.ro.studio.xprocess; singleton :=true
Bundle-Version : 4.1.0
Bundle-Activator : com.icss.ro.studio.xprocess.DeDesignPlugin
Bundle-Vendor : ChinaSoft International
这些项描述了此bundle 的基本属性,注意 Bundle-Activator 描述的是此bundle 的启动/ 停止类。
2 ,依赖关系管理
Require-Bundle :
Import-Package :
这两个描述了此插件需要依赖于那些插件,osgi 会根据此项描述去查找依赖插件,并启动依赖插件。其中 Import-Package 指定要从必需插件中显式导入的所有包。默认情况下,必须为要启动的绑定包解析所有包。还可以将包导入指定为可选项,以支持包不存在的情况。显式导入的类在 Require-Bundle 插件中的包之前解析 。
3 ,导出关系管理
Export-Package
如果别得插件依赖于本插件才能运行,那么我们需要把本插件暴露出去供其他插件调用。
4 ,其他项
Bundle-ClassPath : classpath 路径管理,用来管理所依赖的第三方jar 包。
Eclipse-LazyStart : 是否懒加载项,true 表示当需要调用时才加载。
这些皆可通过Eclipse PDE 来实现可视化编辑,可通过可视化得操作注册到MANIFEST.MF 中。
关于OSGI 的规范还有很多,以上几个是最常见的规范,如果继续学习请参考OSGI R4 规范。在Eclipse 中,Equinox 是OSGI 规范的一个具体实现。打开Eclipse 的安装包会注意到以下一些jar 包(部分):
这些jar 包就是osgi/Equniox 的实现包,我们通过调用或者扩展来实现OSGI 框架。关于Equinox 的介绍请看最后部分
Eclipse 中的Plugin 之间通常存在两种关系,一种为依赖,一种为扩展,对于依赖可通过OSIG 中元描述(即上文降到MANIFEST.MF )信息中加入引用的plugin 即可实现。但是OSGI 是没有定义扩展的,Eclipse 采用了一个Extension Point 方式来实现Plugin 的扩展功能,相当于在eclipse 上又包装了一层,各插件可通过Extension Point 以及Extension 来联系。
对于扩展,Eclipse 采用Extension Point 的方式来实现,每个Plugin 可定义自己的Extension Point ,同时也可实现其他Plugin 的Extension Point ,由于这个在OSGI 中是未定义的,在Eclipse 中通过在plugin.xml 中进行描述,描述的方法为通过<extension-point id="" name="" schema=""> 的形式来定义Plugin 的扩展点,通过<extension point =""> 的形式来定义实现的其他Plugin 的扩展点,所提供的扩展点通过schema 的方式进行描述,详细见eclipse extension-point schema 规范。
关于Extension Point 可举个场景,如工具栏就是工具栏Plugin 提供的一个扩展点,其他的Plugin 可通过此扩展点添加按钮至工具栏中,并可相应的添加按钮所对应的事件( 当然,此事件必须实现工具栏Plugin 此扩展点所要求的接口) ,工具栏的Plugin 将通过 callback 的方式来相应的响应按钮的动作。可见通过Extension Point 的方式可以很好的提供Plugin 的扩展方式以及实现扩展的方式。
以下是摘抄技术论坛的章节,简要通俗,把Eclipse 的基本机制说得很清楚,供参考。若深入再需看相关代码
Eclipse 的实现机制以及过程
架构上来讲Eclipse 基本采用的是Kernel+Core Plugins+Custom Plugins 的结构体系,除了Kernel 部分外均为Plugin ,Eclipse 的OSGI 概念中主要分为了Bundle 和 Service ,可以认为Bundle 是一个模块的管理器,主要是通过BundleActivator 管理模块的生命周期,而Service 则是这个模块可暴露对外的服务对象,这里体现了OSGI 和传统的Plugin Framework 不同的一个地方,管理和静态结构分开,在OSGI 中通过在manifest.mf 文件中增加一些内容来发布Bundle ,在其中描述了 Bundle 的提供商、版本、唯一ID 、classpath 、暴露对外的包、所依赖的包;每个Bundle 拥有自己的ClassLoader 以及 context ,通过context 可进行服务的注册、卸载等,这些操作都会通过事件机制广播给相应的其他的Bundle ;一般来说都为通过在 Bundle 中编写初始需要注册的服务的方法来完成Bundle 可供外部使用的服务的暴露功能;如需要调用其他Plugin 提供的服务可通过 context 的getServiceReference 先获取Service 的句柄,再通过 context.getService(ServiceReference) 的方法获取Service 的实体。
遵循OSGI ,Eclipse 首先是实现了一个OSGI Impl ,这个主要通过它的FrameWork 、BundleHost 、ServiceRegistry 、BundleContextImpl 等对象来实现,实现了Bundle 的安装、触发、卸载以及Service 的注册、卸载、调用,在Plugin 机制上 Eclipse 采用的为lazy load 的方式,即在调用时才进行实际的启动,采用的为句柄/ 实体的方式来实现,外部则通过OSGI 进行启动、停止等动作,各Plugin 则通过 BundleContext 来进行服务的注册、卸载和调用。
那么Extension Point 方面Eclipse 是如何实现的呢,在加载Plugin 时,Eclipse 通过对plugin.xml 的解析获取其中的
通过对Eclipse 启动过程的分析,可清晰的看到Eclipse Kernel+Core Plugins+Application Plugins 的方式,在代码中分别对应为loadBasicBundles 和 registerApplicationServices ,loadBasicBundles 通过加载config.ini 中的osgi.bundles 完成基本的bundles 的加载,去看看这个配置会发现是org.eclipse.core.runtime 还有一个 update ,core.runtime 又会通过IDEApplication 来完成整个Eclipse 的启动,同时会注册所有与workbench 相关的plugin 。
Equinox 介绍
Equinox 项目是Eclipse 开源组织提供的OSGi 框架的实现。Eclipse 自 3.0 版本开始,其内核移植到OSGi 框架上。通过OSGi 框架强大的组件控制,交互和管理能力,再加上Eclipse 插件的自有特点,Eclipse 开 源框架得到了跳跃式的发展。同时,OSGi 规范得益于Eclipse IDE 环境庞大的使用者,OSGi 联盟也进入了快速发展时期。
OSGi 的本质是将Java 面向对象的开发转向面向组件和服务的开发。OSGi 框架提供了一套完善的机制用于管理和控制组件(Bundle )、服务(Service )的生命周期,以及组件和服务在其生命周期内的交互。
本文及后续系列文章将以Equinox 项目为基础,讲述如何实现基于OSGi 的应用。
Equinox 项目包括OSGi R4 版本规范核心框架的实现,一系列OSGi 标准服务Bundle 及运行基于OSGi 的系统的一些基础构件。用户可以直接访问该项目在Eclipse 的网 址Equinox 获取概括性的信息。目前,关于Equinox 的进展大部分资料及项目进展存在于Eclipse Wiki 上。
目前,Equinox 项目包括OSGi 核心框架的实现,OSGi 标准服务Bundle 实现,OSGi 的服务器端(J2EE 实现)应用,Equinox 部署更新框架及一些研究方向(未成熟发布的构想如JMX 管理,安全管理,面向方面的设计与应用等)。
2.1OSGi 核心框架的实现
Equinox 的OSGi 核心实现由三部分组成,包括:
Ø OSGi 核心规范的实现(org.eclipse.osgi )
该项目是OSGi 核心框架标准规范的实现。由于Eclipse 在3.0 版本之前未采用 OSGi 作为系统内核,所以,为了重用Eclipse3.0 以前核心系统的代码,Equinox 的OSGi 实现在一定程度上显得比较繁冗。用户如果想研究 开源的OSGi 框架实现的源代码,可以从Oscar (目前为Apache 的Felix 项目)或Knopflerfish 项目着手。ObjectWeb 上的 Oscar 项目最初实现OSGi R2 版本框架时,整个核心的源代码不超过40 个类文件。现在,Oscar 项目转由Apache 维护,项目称之为Felix ,目前已发布1.0 版本。 Knopflerfish 也是很早实现OSGi 的一个开源项目,该项目的网站上提供了很多关于OSGi 编程的注意事项。
Ø OSGi 框架启动支持(org.eclipse.equinox.launcher )
OSGi 框架启动支持对于Eclipse IDE 开发环境熟悉的开发用户来说并不算陌生。使用Eclipse 以前版本的用户会发现在Eclipse 安装目录下有一个startup.jar 的文件, 该文件是Eclipse 开发环境的入口程序封装。Equinox 将该Jar 文件的实现迁移为一个独立的OSGi Fragment 。该Fragment 主要是帮助Equinox 建立起运行环境,如类加载路径,运行配置参数等等。
Ø Equinox 启动可执行程序
Equinox 启动可执行程序即为eclipse.exe 文件,该执行程序并不是 Eclipse 以前版本的exe 可执行文件,而是由原来的eclipse.exe 程序拆分而来,该执行文件的一部分功能拆分为一个共享DLL ,放置在 OSGi 框架启动支持段项目(org.eclipse.equinox.launcher )中,与原来的Eclipse 根目录下的startup.jar 文件功能合并。
2.2OSGi 标准服务Bundle 实现
OSGi 在提出核心框架规范的同时为一些常用的服务如日志服务(LogService ),配 置管理服务(Config Admin ),事件管理服务(Event Admin ),HTTP 服务(HTTP Service )等。Equinox 提供了大部分OSGi 标准服务的bundle 的实现,同时,借助于Eclipse 环境的一些自身的特 点,Equinox 在实现这些OSGi 标准服务的同时,提供了很多功能扩展服务(如org.eclipse.equinox.common )。
Equinox 项目目前提供的OSGi 标准服务实现如下所示:
Equinox 实现项目 |
服务名称 |
服务说明 |
org.eclipse.equinox.app |
Application Container |
该项目实现了OSGi R4 MEG 中的应用程序容器服务 |
org.eclipse.equinox.common |
Common Utility Bundle |
由一组Eclipse 工具类(如IStatus ,Assert ,IAdaptable 等)组成的实用程序Bundle 。该Bundle 也可以在非OSGi 环境中独立使用。 |
org.eclipse.equinox.device |
Device Access Service |
OSGi R4 规范中的Device Access Service 标准服务的实现,该组件由Prosyst 公司提供实现。 |
org.eclipse.equinox.ds |
Declarative Services |
OSGi R4 规范中的Declarative Service 标准服务的实现,该组件由Prosyst 公司提供实现 |
org.eclipse.equinox.event |
Event Admin Service |
OSGi R4 规范中的事件管理服务的实现。 |
org.eclipse.equinox.http |
HTTP Service |
OSGi R4 规范中的HTTP 服务实现 |
org.eclipse.equinox.log |
Log Service |
OSGi R4 规范中的日志服务实现 |
org.eclipse.equinox.metatype |
Metatype Service |
OSGi R4 规范中的Metatype 服务的实现 |
org.eclipse.equinox.preferences |
Preferences Service |
OSGi R4 规范中的Preferences 服务的实现 |
org.eclipse.equinox.registry |
Extension Registry |
Equinox 提供的Ecipse 扩展点(extension point )注册表服务 |
org.eclipse.equinox.supplement |
Supplemental Bundle/JAR |
Equinox 提供的一组Equinox 实现所使用的类型库 |
org.eclipse.equinox.useradmin |
User Admin Service |
OSGi R4 规范中的用户管理服务实现 |
org.eclipse.equinox.wireadmin |
Wire Admin Service |
OSGi R4 规范中的服务通信拓扑管理服务 |
org.eclipse.osgi.services |
OSGi Services API |
OSGi R4 规范中的服务接口定义,该Bundle 由OSGi 联盟定义的服务API 接口组成 |
org.eclipse.osgi.util |
OSGi Utilities |
OSGi R4 规范中的工具类接口及接口实现Bundle |
2.3OSGi 的服务器端(J2EE 实现)应用
Equinox 实现了OSGi 在J2ME 、J2SE 方面的应用的同时,也推动了OSGi 在 J2EE 方面的应用。Equinox 提供了一组基础的Bundle ,使得使用JSP 、Servlet 和Struts 等J2EE 技术的Web 应用项目可以运 行于Equinox OSGi 环境中。同样的,Equinox 通过一组Bundle ,可以将Equinox OSGi 应用嵌入到现有的Web 服务器(如Tomcat ,Jetty 等)和应用服务器(如Websphere ,Weblogic 等)中。
下面是Equinox 在J2EE 应用方面的一组Bundle 列表:
Equinox J2EE 实现项目 |
服务名称 |
服务说明 |
|
org.eclipse.equinox.http |
HTTP service |
该Bundle 是OSGi R4 规范中的HTTP 服务的标准实现。目前该实现只支持Servlet 2.3 。 |
|
org.eclipse.equinox.http.registry |
HTTP registry |
该Bundle 支持使用Eclipse 的扩展注册表注册servlet ,文件资源和JSP 而不是使用OSGi 中的代码注册机制。 |
|
org.eclipse.equinox.servletbridge |
Servlet Bridge |
该Bundle 提供一个底层的Hook servlet ,使得Equinox 可以嵌入到现有的应用服务器中运行。该Bundle 中的servlet 启动嵌入的Equinox 并使其可以处理来自底层应用服务器接收的HTTP 请求。 |
|
org.eclipse.equinox.http.servlet |
HTTP Servlet |
该Bundle 为在Equinox 中发布其他servlet 处理引擎(如传统的应用服务器)为OSGi HTTP 服务提供支持。 |
|
org.eclipse.equinox.http.servletbridge |
HTTP ServletBridge |
该Bundle 为底层的应用服务器(如Tomcat ,Jetty 等)发布为OSGi HTTP 服务提供一层封装。封装的应用服务器必须安装该servlet bridge 。 |
|
javax.servlet |
Servlet API |
Servlet 规范标准接口API 的Bundle 封装。 |
|
javax.servlet.jsp |
Servlet JSP API |
Servlet JSP API 接口的Bundle 封装。 |
|
org.mortbay.jetty |
Jetty |
嵌入式Jetty 实现的Bundle 封装。目前Equinox 提供的Jetty 实现版本为5.x 。 |
|
org.eclipse.equinox.http.jetty |
HTTP Jetty |
该Bundle 封装Jetty 为标准的OSGI HTTP 服务。目前该服务只能使用Jetty 5.x 版本;如果用户希望使用Jetty 6.x 版本的Bundle 封装,可以参考ops4j 上的实现。 |
|
关于如何在Equinox 环境中部署Web 应用(JSP 、Servlet 和Struts 等),请参考Equinox 网站相关资料。我会在本系列后续文档中给出详细介绍。
2.4Equinox 部署更新框架(Provisioning )
Eclipse 提供为插件的分组,更新及远程维护提供了一套完善的机制。用户可以通过远程更 新站点安装或升级所需功能的插件。为了适应OSGi 环境的特点,Equinox 项目组为基于OSGi 的系统的部署更新提供了一套全新的框架,称为 “equinox p2” 。目前该框架还在第一个发布版本的最后阶段,该功能预计将在Eclipse 3.4 版本中集成发布。
2.5Equinox 的最新研究方向
Ø 资源管理(Resource Monitoring )
该方向致力于为基于OSGi 的系统提供一个轻量级的资源监控管理基础框架,该框架基于JMX 技术。目前该研究方向已经提供了一套可供展示的基本实现。
Ø 安全管理
该方向致力于将Java 安全机制(JCA/JAAS 框架)集成到Eclipse 中。为 Eclipse/Equinox 环境提供诸如消息摘要,数字签名,密钥存储,证书存储等基础安全机制。此外,该方向还为Eclipse 提供JAVA 包签 名,Bundle 加载时的签名校验,代码权限等机制的实现。
Ø 面向方面的开发
该方向致力于解决在OSGi 环境中面向方面编程的一些技术问题,如加载编排和模块化等。
3. 结论与参考
本文简要概述了Equinox 在OSGi 规范方面的实现以及它为OSGi 在其他领域的应用所做的研究。后续文档中,我们将会将上述各个方面展开进行详细的描述。OSGi 的广泛应用将大大推动JAVA 由面向对象的编程向面向组件和服务的编程转变。
目前,JCP 组织提出JSR-291 将OSGi 纳入JAVA 标准规范。如果该JSR 最终被集成到J2SE 实现中,开发人员可以在JAVA 基础编程中直接采用OSGi 提供动态的模块化应用。
Equinox 项目源代码的位置位于CVS 服务器 上::pserver:anonymous:dev.eclipse.org/cvsroot/eclipse 路径下,以 org.eclipse.equinox.* 命名的项目以及该位置下的equinox-incubator 目录下。
4. 插曲
SUN 公司提出了一个类似于OSGi 的模块化系统规范称之为“HK2” 。HK2 的全称为 “Hundred Kilobytes Kernel” ,包括Modules Subsytem 和Component Model 两部分。据称,该内核将在JDK 7 中集成,同时,SUN 在其开源的GlassFish J2EE 应用服务器项目V3 版本中将HK2 作为其系统内核实现。