Eclipse3.0平台Plugin Framework简介

  Eclipse3.0平台简介
Eclipse3.0平台与Eclipse2.1平台的一个重要的区别就是,Eclipse3.0平台建立在一个Java框架上,即 Open Services Gateway Initiative( OSGi)服务平台. OSGi的采用,使Eclipse走上了完全动态平台的发展道路.本文先简要介绍 OSGi框架,然后介绍 OSGi框架和Eclipse3.0平台的联系.

Eclipse3.0平台简介
作者:张增志


概要
Eclipse3.0平台与Eclipse2.1平台的一个重要的区别就是,Eclipse3.0平台建立在一个Java框架上,即Open Services Gateway Initiative(OSGi)服务平台.OSGi的采用,使Eclipse走上了完全动态平台的发展道路.本文先简要介绍OSGi框架,然后介绍OSGi框架和Eclipse3.0平台的联系.
概要
Eclipse3.0平台与Eclipse2.1平台的一个重要的区别就是,Eclipse3.0平台建立在一个Java框架上,即Open Services Gateway Initiative(OSGi)服务平台.OSGi的采用,使Eclipse走上了完全动态平台的发展道路.本文先简要介绍OSGi框架,然后介绍OSGi框架和Eclipse3.0平台的联系.

 

 


一.  OSGi框架简介
URL:http://blog.blogchina.com/upload/2004-11-24/20041124110530659453.jpg
图1:Eclipse3.0架构
如上图所示,Eclipse3.0平台是建立在OSGi(Open Services Gateway Initiative)服务平台基础之上的,所以有必要先介绍一下OSGi框架.
OSGi框架
OSGi框架是一个通用,安全,可管理的Java框架,它支持被称为"bundle"的可扩展和可下载的服务应用的部署.与OSGi兼容的设备可以下载和安装基于OSGi标准的bundle,并且还可以删除不再需要的bundle.另外,已安装的bundle可以注册一组服务(service),这些服务可以在OSGi框架的严格控制下被其他bundle共享.
OSGi框架以一种动态和可升级的方式管理哪些处于OSGi环境中的bundle的安装和更新,还管理bundle和服务(service)的依赖关系.
Bundle
在OSGi服务平台中,bundle是部署的Java应用的唯一实体.一个bundle由Java类和其它资源组成,它们提供功能给终端用户,提供服务组件(serveices)给其它的bundle.
Bundle是作为JAR文件被部署的.可以说,一个bundle就是一个JAR文件,它包括:
1>     容纳了实现零个或多个服务的资源.这些资源可以是Java类文件,也可以是其它数据文件如HTML文件,图标文件等.
2>     容纳了一个manifest文件.该文件描述了JAR文件的内容和与bundle相关的配置信息.
3>     陈述了对其他资源如Java中的包(package)的依赖关系.
4>     指明bundle中的一个Java类作为Bundle Activator接口的实现类.OSGi框架必须实例化该类并调用start和stop方法来启动和停止bundle.
MANIFEST.MF文件
每一个bundle都有一个描述其自身信息的MANIFEST.MF文件,该文件位于JAR文件中的META-INF目录下.
我们知道,在生成普通的Java JAR文件时都会要求指定一个MANIFEST.MF文件与该JAR文件关联在一起.MANIFEST.MF文件的内容格式可能如下:

Manifest-Version: 1.0

Ant-Version: Apache Ant 1.5.3

Created-By: 1.4.2_04-b05 (Sun Microsystems Inc.)


在OSGi框架中,每一个bundleMANIFEST.MF文件除了可以包括上述内容外,还定义了自己的OSGi MANIFEST内容格式,例如:

Manifest-Version: 1.0

Ant-Version: Apache Ant 1.5.3

Created-By: 1.4.2_04-b05 (Sun Microsystems Inc.)
Bundle-Activator: test.osgi.exam2.Activator
Export-Package: test.osgi.exam2.service
Bundle-Name: English dictionary
Bundle-Description: A bundle that registers an English dictionary service
Bundle-Version: 1.0.0


上例中显示的是一组MANIFEST头(header)/值(value)对,如Bundle-Activator头(header)的值为test.osgi.exam2.Activator.
在OSGi框架定义了一组标准的MANIFEST头(header),每一个header都有其特定的含义.上例中定义的Bundle-Activator头信息的值test.osgi.exam2.Activator表示用来启动和停止"English dictionary" Bundle的类名. Export-Package头信息的值test.osgi.exam2.service表示可以被导出的包名,即test.osgi.exam2.service包可以被其它Bundle导入并使用其中提供的服务(service).
Bundle的受控状态
一个Bundle可能处在下面的状态之中:
■     已安装(installed)
在OSGi框架安装Bundle时,将解析该Bundle的本地代码的依赖关系.如果失败,该Bundle将不会被安装.一旦Bundle被安装,OSGi框架将可对该Bundle的整个生命周期(如起动,停止,更新,卸载)进行控制.
■     已解析(resolved)
当OSGi框架成功地解析Bundle的本地代码的依赖关系时,该Bundle就进入解析状态.这些依赖关系包括:
1>     BundleMANIFEST.MF文件中,MANIFESTBundle-Classpath定义的类路径依赖关系.
2>     BundleMANIFEST.MF文件中,MANIFESTExport-PackageImport-Package定义的依赖关系.
■     起动(starting)
一旦Bundle被起动,该Bundle的状态就被设置为ACTIVE,并一直持续到该Bundle被停止.在起动前,MANIFEST.MF文件中MANIFEST头Bundle-Activator定义的类将被实例化,该类实例的start方法被调用以起动Bundle.
■     停止(stopping)
一旦Bundle被停止,该Bundle的状态就被设置为RESOLVED.在停止前,上文中提到的Bundle-Activator类定义的stop方法被调用以停止Bundle.
■     激活(active)
已经被激活的Bundle可以进行自身状态的更新.在任何时候,OSGi框架只能满足一个Bundle的唯一版本可用.Bundle的更新操作支持该Bundle移植到一个高版本或向后兼容的版本.
■     已卸载(uninstalled)
在卸载前,上文中提到的Bundle-Activator类定义的uninstall方法被调用以卸载Bundle,该方法将使OSGi框架提醒其他Bundle它正在进行卸载操作,并设置该Bundle的状态为UNINSTALL.如果该Bundle与其他Bundle存在关系,如它导出一些被其他Bundle使用的包(即该Bundle的MANIFEST文件中定义了Export-Package值),OSGi框架在没有被重启的情况下将继续确保这些包仍可用.如果该Bundle与其他Bundle没有关系,OSGi框架将恢复到该Bundle被安装前的状态.
下面的Bundle状态图描述了Bundle的受控状态.
URL:http://blog.blogchina.com/upload/2004-11-24/20041124110552991489.jpg
图2
类装载(Class Loading)
Bundle就是一个JAR文件,OSGi框架所面临的首要问题就是,怎样去获取随时可能被"扔进"框架中的Bundle内的类文件和其它资源.
对于每一个已安装或已解析的Bundle,OSGi框架都会建立该Bundle的Classloader.这个Classloader还被建立在下面图3所示的委托模型中.
URL:http://blog.blogchina.com/upload/2004-11-24/20041124110606586667.jpg
图3
其中:
1>     Bootstrap类装载器装载Java核心API中的类.
2>     SystemClassLoader类装载器可以是系统类路径类装载器和标准扩展类装载器,还可以是其他用户自定义类装载器,装载系统CLASSPATH上的类或Java扩展路径上的类或用户指定的类.
3>     BundleClassLoader类装载器装载该Bundle的MANIFEST文件中Bundle-ClassPath头所指定的类文件.如果该Bundle需要导入其它Bundle中导出的包,那么这些Bundle的类装载器的实例也要被建立在如图3所示的委托模型中,并为该Bundle提供它所需的类.
上文中只是对OSGi框架进行了简短地介绍,关于它的详细信息请参照: http://www.osgi.org
二.  Eclipse3.0插件和OSGi Bundle
OSGi服务平台规范是一个开放的架构,用户可以根据自己的需要来实现这个规范.Eclipse3.0就提供了该规范的一个实现.
我们知道,在OSGi中基本的模块单元是Bundle,在Eclipse中则是插件(plug-in).在Eclipse2.1中,插件往往表现为plugins目录下的一个文件夹.例如如下的目录结构:
    + D:\eclipse
        + plugins
            + eclipseme
                + docs
                + icons
                + lib
                - about.html
                - CHANGES.txt
                - CREDITS.txt
                - eclipseme.jar
                - JETTY-LICENSE.html
                - LICENSE.txt
                - plugin.properties
                - plugin.xml
                - README.txt
                - toc.xml
            + org.apache.ant_1.5.3
上述eclipseme插件提供了Eclipse2.1平台和J2ME的集成.在每一个Eclipse2.1插件中,都包含一个plugin.xml文件,其中描述了插件名,版本号,需要的JAR包和插件要使用的扩展点等等.
■ plugin.xml   插件清单文件
■ plugin.properties   容纳被plugin.xml引用的字符串.
■     about.html   证书信息
■     *.jar   插件需要的类文件
■     lib   容纳第三方JAR包
■     icons   容纳icon文件,通常是GIF格式
■     docs   容纳文档文件,通常是HTML格式
■     toc.xml   文档结构清单文件
■     (other files)
Eclipse3.0中,插件不仅表现为plugins目录下的一个文件夹,还包括一个MF文件.这个MF文件可以位于该插件文件夹下.也可位于configuration\org.eclipse.osgi\manifests目录下.如:
1:
    + D:\eclipse
        + configuration
            + org.eclipse.osgi
                + manifests
                    - eclipseme_0.1.0.MF
2:
    + D:\eclipse
        + plugins
            + org.eclipse.osgi_3.0.0
                + META-INF
                    - MANIFEST.MF
Eclipse3.0中,插件也可被称为Bundle.Bundle的类文件和资源文件就是插件文件夹下的JAR文件和其他资源文件,Bundle的MANIFEST文件就是上文中提到的MF文件.
Eclipse的插件信息是被配置在plugin.xml中的.OSGi Bundle信息是被配置在MANIFEST.MF文件中的.下面就说说它们的联系.
plugin.xml包括三个部分的信息.
1>     插件基本信息.如插件名,插件ID号,插件版本号,插件提供者名和插件类的全限定名.
2>     插件的依赖关系和插件的运行库.
3>     插件的扩展和扩展点.
Eclipse3.0中,前两部分的信息可以被配置在MANIFEST.MF文件中.如Eclipse3.0中的runtime插件.考虑到与Eclipse以前版本的兼容,plugin.xml文件仍然支持对上三部分信息的配置格式.但是,Eclipse3.0平台运行在处理插件信息时,它认为插件是一个Bundle外加上扩展和扩展点.
Eclipse2.1的平台运行内核缓存所有插件的注册信息在Registry API中,所有这些信息是从.registry文件中或解析所有的plugin.xml文件(安装新插件的情况下)获取的.在Eclipse3.0中,Registry API已经不被建议使用,对所有插件的注册信息的缓存已被重构为两部分,一是Bundle数据,另外是ExtensionRegistry API,它们分别从.bundledata.state文件和.registry.X文件中获取.这三个文件是Eclipse生成的,它们的数据来源是各个插件的plugin.xmlMANIFEST.MF文件.当平台安装新的插件时,它们都将被重新生成.之所以从它们中而不是直接解析plugin.xmlMANIFEST.MF文件,是要Eclipse起动更快.
Eclipse3.0中,有些插件文件夹下并没有MANIFEST.MF文件,这是为了兼容Eclipse以前版本的插件.对于每一个已被Eclipse3.0安装(installed)的插件(Bundle),系统都会生成一个MF文件在configuration\org.eclipse.osgi\manifests目录下(已经有MANIFEST.MF文件的插件除外).被生成的MF文件内容只是该插件的plugin.xml文件中扩展点外的部分数据.


于作者:本文作者增志,目前在中国北京先数通信息技有限公司工作,从事Java方面的开发和研究。
Email[email protected]
联系地址:北京市海淀区车道沟1号滨河大厦D6
邮编:100089

 ------------------------------------------------------------------------------------------------------

概述
Eclipse中最出彩的部分莫过于它的Plugin Framework,可以说Eclipse在一定程度上使得Plugin机制得以流行,当然,Eclipse的优势不仅仅在此,但正因为采用了Plugin机制,Eclipse才得以被不断的扩充,越来越强大。一直以来就想分析Eclipse的Plugin Framework,由于各种原因一直耽搁,刚好这个周末没什么事,下定决心对其进行了研究和分析,方法很原始,就是对Eclipse的启动过程进行分析,基于的是Eclipse 3.1的版本,分析过程就不在这说了,主要是说说分析出来的心得。
架构上来讲Eclipse基本采用的是Kernel+Core Plugins+Custom Plugins的结构体系,除了Kernel部分外均为Plugin,所以可称为all are plugins,凡是Plugin的部分都是可被替换的。

OSGI
Eclipse 3.0后采用的是OSGI来作为其Plugin Architecture实现的依据,鉴于此就得简单提提OSGI了,主要从Plugin的角度来分析OSGI,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的实体。

Eclipse Plugin定义
Eclipse中的Plugin的概念为包含一系列服务的模块即为一个Plugin。既然是遵循OSGI的,也就意味着Plugin通常是由Bundle和N多Service共同构成的,在此基础上Eclipse认为Plugin之间通常存在两种关系,一种为依赖,一种为扩展,对于依赖可通过OSGI中元描述信息里添加需要引用的Plugin即可实现,但扩展在OSGI中是没有定义的,Eclipse采用了一个Extension Point的方式来实现Plugin的扩展功能。
结合OSGI
Eclipse遵循OSGI对于Plugin的ID、版本、提供商、classpath、所依赖的plugin以及可暴露对外的包均在manifest.mf文件中定义。
Plugin Extension Point
对于扩展,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规范,为了更好的说明扩展点这个概念,举例如下,如工具栏就是工具栏Plugin提供的一个扩展点,其他的Plugin可通过此扩展点添加按钮至工具栏中,并可相应的添加按钮所对应的事件(当然,此事件必须实现工具栏Plugin此扩展点所要求的接口),工具栏的Plugin将通过callback的方式来相应的响应按钮的动作。可见通过Extension Point的方式可以很好的提供Plugin的扩展方式以及实现扩展的方式。

Eclipse Plugin Framework
那么Eclipse是如何做到Plugin机制的实现的呢??还是先讲讲Eclipse的设计风格,Eclipse在设计时有个重要的分层法则,即语言层相关和语言层无关的代码分开(如jdt.core和core),核心与UI分开(如workbench.ui和workbench.core)这两个分层法则,这个在Eclipse代码中处处可见,在Plugin Framework部分也充分得体现了这个,遵循OSGI,Eclipse首先是实现了一个OSGI Impl,这个主要通过它的FrameWork、BundleHost、ServiceRegistry、BundleContextImpl等对象来实现,如果关心的话大家可以看看这部分的代码,实现了Bundle的安装、触发、卸载以及Service的注册、卸载、调用,在Plugin机制上Eclipse采用的为lazy load的方式,即在调用时才进行实际的启动,采用的为句柄/实体的方式来实现,外部则通过OSGI进行启动、停止等动作,各Plugin则通过BundleContext来进行服务的注册、卸载和调用,这是OSGI的部分实现的简单介绍。
那么Extension Point方面Eclipse是如何实现的呢,在加载Plugin时,Eclipse通过对plugin.xml的解析获取其中的<extension-point>节点和<extension>节点,并相应的注册到ExtensionRegistry中,而各个提供扩展点的Plugin在提供扩展点的地方进行处理,如工具栏Plugin提供了工具栏的扩展点,那么在构成工具栏时Plugin将通过Platform.getPluginRegistry().getExtensionPoint(扩展点ID)的方法获取所有实现此扩展点的集合IExtensionPoint[],通过此集合可获取IConfigurationElement[],而通过这个就可以获取<extension point="">其中的配置,同时还可通过IConfigurationElement创建回调对象的实例,通过这样的方法Eclipse也就实现了对于Plugin的扩展以及扩展的功能的回调。在Plugin Framework中还涉及很多事件机制的使用,比如Framework的事件机制,以便在Bundle注册、Service注册的时候进行通知。

总结
通过对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。
Eclipse由于以前版本的Plugin Framework是没有采用OSGI的,所以通过EclipseAdaptor的方式来实现与以往的兼容,目前新的Plugin采用的方式基本就是manifest.mf描述Plugin OSGI部分的信息,Plugin.xml描述扩展点的信息。
Eclipse中有非常多优秀的设计,这个在看它的代码时会有很深的感触,比如Contributing to Eclipse中提到的Extension Object/Interface的设计,确实是非常的不错,虽然看到你可能觉得很简单,关键是要想得到并合适的去使用。
总结陈词,^_^,Eclipse Plugin Framework是采用OSGI Impl+Plugin Extension-Point的方式来共同实现的,实现了Plugin的部署、编写、独立的Classloader和Context、Plugin中Service的注册、Plugin中Service的调用、Plugin的依赖、Plugin的扩展、Plugin生命周期的管理。

带来的思考
Eclipse Plugin Framework采用的是OSGI的实现,一定程度上我们也能看到OSGI的优点,那么JMX+IoC方式的Plugin Framework与其的比较又是在哪些方面呢?Eclipse Plugin Framework不足的地方又在哪里呢?哪些地方值得改进呢?

 

你可能感兴趣的:(eclipse,框架,应用服务器,ant,osgi)