这是Lifecycle Layer中的最大改进,在之前的规范中只是简单的描述了下框架的启动和关闭,在制定了这个规范后,以后无论是启动equinox还是felix,都可采用同样的方式启动,详细的来看看,本文摘自《OSGi原理与最佳实践》。
首先来看看外部应用如何通过Framework的API来实现Framework的启动,来看张启动方法的时序图先:
这个时序图完整的说明了如何通过Framework的API来实现OSGi Framework的启动和停止:
n 调用FrameworkFactory的newFramework方法
所有OSGi的实现都必须实现FrameworkFactory接口,此接口中只有一个方法,即newFramework(Map configuration),外部容器在实例化FrameworkFactory实现对象上有两种做法:
A. Class.forName(FrameworkFactory实现类).newInstance()
B. 通过Java 6中提供的ServiceLoader寻找并加载FrameworkFactory的实现类,使用方法为:
假设com.acme.osgi.Factory是FrameworkFactory的实现类,那么则在META-INF下新建services目录,在此目录下建立一个org.osgi.framework.launch.FrameworkFactory的文件,文件内容即为:com.acme.osgi.Factory,在程序中则这么编写来加载此FrameworkFactory实现类:
ServiceLoader<FrameworkFactory> sl=ServiceLoader.load(FrameworkFactory.class);
Iterator<FrameworkFactory> it=sl.iterator();
在创建了FrameworkFactory实现的实例后,就可调用newFramework方法了,newFramework方法中的Map参数为控制OSGi框架行为的一些配置项,关键的有:
n org.osgi.framework.bootdelegation
配置哪些package需要从boot classloader中加载,配置的值可为com.acme.*或com.acme.services。
n org.osgi.framework.executionenvironment
配置Framework执行所需的环境,例如J2SE-1.5。
n org.osgi.framework.library.extensions
native code的扩展名配置,例如so,dll。
n org.osgi.framework.startlevel
配置Bundle启动级别。
n org.osgi.framework.storage
配置用于存储OSGi应用运行时的Bundle状态等信息的路径,当此路径不存在时,框架应负责进行创建,如创建失败则抛出异常。
n org.osgi.framework.storage.clean
配置storage目录是否要清除,例如值配置为onFirstInit,意味着当Framework Bundle第一次初始化之前,storage目录将被清空,这个配置项的好处是可以控制Framework重启后是否需要根据上次运行时的状态来启动。
n org.osgi.framework.system.packages
Framework的parent ClassLoader应对外export的packages。
n org.osgi.framework.system.packages.extra
在上面的配置项的基础上增加了扩展属性的配置,例如:
org.osgi.framework.system.packages.extra=org.acme.foo;version=1.2
n org.osgi.framework.bundle.parent
和equinox中的osgi.parentClassLoader属性的含义一样,用于控制boot classloader具体是哪个classloader,有四个可选的属性值:boot、app、ext、framework,含义和equinox完全相同。
根据需要给这些属性配置相应的值后,即可调用newFramework方法创建出Framework对象了。
n 调用Framework的init方法
在init方法中完成Bundle Context的创建以及Framework services的注入。
n 通过Framework获取BundleContext
n 安装Bundle
通过BundleContext.installBundle来安装需要的Bundle。
n 调用Framework的start方法
Framework将StartLevel service设置为指定的启动级别,从而促发已安装的所有的Bundle的resolve和启动。
n 调用Framework的waitForStop方法
调用此方法,等待Framework的停止运行。
按照以上说明,一个典型的基于OSGi R4.2规范的OSGi Framework的启动过程代码编写示例如下:
Map p=new HashMap();
p.put(“org.osgi.framework.storage”,System.getProperties(“user.home”)+File.separator+”osgi”);
FrameworkFactory factory=Class.forName(factoryClassName).newInstance();
Framework framework=factory.newFramework(p);
framework.init();
BundleContext context=framework.getBundleContext();
…//安装Bundles
framework.start();
framework.waitForStop();
对比Felix的启动代码,是不是觉得有点相似呢?
OSGi规范中对Framework的生命周期也做了详细的说明,图示如下:
具体来看看init、start以及stop Framework时会做哪些事情。
n init
init后,需要做到以下效果:
启动事件分发处理功能;
配置好Security Manager;
StartLevel设置为指定的startlevel,默认为0;
创建可用的BundleContext对象;
所有安装的Bundles的状态均设置为INSTALLED;
Framework提供的services都可用;
Framework的状态为STARTING。
n start
负责根据StartLevel启动相应的已安装的Bundle,如Bundle启动失败,则广播Framework.ERROR的事件,启动完毕后Framework的状态为ACTIVE。
n stop
负责停止所有运行的Bundle,释放所有的资源,并将Framework的状态置为RESOLVED。
n update
停止Framework,并给Framework.waitForStop方法返回STOPPED_UPDATE或STOPPED_BOOTCLASSPATH_MODIFIED事件值,然后应用代码应自行完成update处理。
在Framework规范中,OSGi还说明了Framework运行于多线程模式下,即所有Bundle都运行在各自的线程中,基于事件机制来响应其他Bundle的事件。
从以上改动来看,增加的 Framework 章节是最大的改动, Framework 规范的制定吸取了 Felix 以及 Equinox 的优点,对于统一 OSGi Framework 的启动方式以及行为将起到很大的作用,尤其是对于嵌入 OSGi 框架的应用以及需要与其他容器集成的 OSGi 应用而言会有很大的帮助。