OSGI之生命周期层

前言

 

Java模块化编程是将来发展的一种趋势,虽然JDK对模块化编程的支持来得有点晚,但jdk1.9中发布的Jigsaw(或者应该称之为JPMS)终归还是对模块化编程提供了支持。但相比于OSGI来说,JDK1.9毕竟还没有大范围商用,其模块模块化还没有被大范围验证。OSGI已经很多成熟的案例,索引要学习java的模块化编程,建议还是从OSGI开始。上一篇文章对模块层的规范进行了总结,这次继续对生命周期层进行总结。

 

OSGI规范在生命周期层定义一些列接口,用来定义和管理Bundle生命周期。这些API又分为两类:

1、在应用程序外部,生命周期层精确的定义了对Bundle生命周期相关的操作接口,实现对OSGI框架中运行的Bundle进行动态的改变。简单的理解就是生命周期层允许你在执行时从外部安装、启动、更新、停止、卸载Bundle,即可以实现所谓的热更新。

2、在应用程序内部,生命周期层定义了一些Bundle访问执行环境上下文的接口,为Bundle提供了一种与OSGI框架交互的途径以及一些执行时的便利条件。

模块层只是依赖于元数据,而生命周期层主要依赖一些API接口,对Bundle进行操作。

 

OSGI框架在生命周期层中的作用:OSGI框架支持了Bundle的生命周期管理:安装、解析、启动、停止、更新、卸载。

 

如何将Bundle挂接到OSGI框架下呢,通过向元数据配置文件(MANIFEST.MF)中添加Bundle激活器Bundle-Activator,配置方式为:Bundle-Activator: com.sky.osgi.api.ApiActivator。其中ApiActivator是自定义的激活器,继承自org.osgi.framework.BundleActivator。这个接口提供了两个方法startstop,注意这两个方法不是启动和停止Bundle的方法,而是在Bundle的启动和停止发生时,需要执行的操作。有点类似于在Spring中配置init-methoddestroy-method

 

换句话说也就是没有在元数据配置文件中配置激活器,Bundle也是可以正常的启动和停止。激活器只是起到让OSGI框架与Bundle连接起来,提供一些钩子API而已。

 

生命周期层API

 

OSGI规范定义的生命周期层API主要分布在三个接口中(具体的实现交给具体的OSGI框架):BundleActivator(激活器)、BundleContexBundle的上下文对象)、BundleBundle对象本身),下面分别来看下这些API

 

BundleActivator激活器

首先就是上面提到的org.osgi.framework.BundleActivator中定义的startstop方法:

public interface BundleActivator {
    void start(BundleContext var1) throws Exception;
    void stop(BundleContext var1) throws Exception;
}

 

当一个BundleOSGI框架中被安装和启动后,会调用start方法,以便做一些初始化处理;当Bundle被停止后,会调用stop方法做一些相应的清理工作。需要注意的是,每次Bundle被启动时会创建一个BundleActivator实例,Bundle被停止后该BundleActivator实例被丢弃,;如果再重启启动该Bundle,又会创建一个新的BundleActivator实例。也就是说在Bundle启动到停止之间,这些操作都是由OSGI框架自己去保证。

 

BundleActivatorstartstop方法只是把Bundle与框架连接起来,真正实现与框架的交互是由BundleContex--Bundle上下文对象提供的相关API实现。可以看到它是startstop方法的参数,并在这两个方法体内部实现与框架的交互。

 

BundleContex上下文对象

BundleContext只是一个接口类,其中定义的API方法 大致分为两类:

1OSGI框架与Bundle部署和生命周期相关的API

2Bundle之间服务式的交互API

换句话说在BundleContext中即定义了与命周期层相关的API,又定义了与“服务层”相关的API。本次总结的主题是生命周期层,所以本次只关注第一类API,大致如如下方法:

public interface BundleContext extends BundleReference {
  String getProperty(String var1);
 
  Bundle getBundle();
  //安装Bundle到OSGI框架,是Bundle生命周期的入口
  Bundle installBundle(String var1, InputStream var2) throws BundleException;
  //安装Bundle到OSGI框架,是Bundle生命周期的入口
  Bundle installBundle(String var1) throws BundleException;
  //根据id获取Bundle
  Bundle getBundle(long var1);
  //获取框架中所有的Bundle列表
  Bundle[] getBundles();
  //添加Bundle状态变更监听器
  void addBundleListener(BundleListener var1);
  //移除Bundle状态变更监听器
  void removeBundleListener(BundleListener var1);
  //添加框架操作监听器
  void addFrameworkListener(FrameworkListener var1);
  //移除框架操作监听器
  void removeFrameworkListener(FrameworkListener var1);
  //根据url获取Bundle
  Bundle getBundle(String var1);
  //省略其它"服务层"方法
}
 

 

Bundle接口

每个已安装到OSGI框架的Bundle,都对应会生成一个Bundle对象。Bundle接口是OSGI规范定义的一系列操作Bundle对象方法,用于管理已经安装的Bundle的生命周期,

public interface Bundle extends Comparable<Bundle> {
    // Bundle生命周期内不同的状态常量
    int UNINSTALLED = 1;//卸载状态
    int INSTALLED = 2;//已安装状态
    int RESOLVED = 4;//已解析状态
    int STARTING = 8;//启动中
    int STOPPING = 16;//停止中
    int ACTIVE = 32;//激活状态
    //省略其它
    //获取当前状态
    int getState();
    //启动Bundle
    void start(int var1) throws BundleException;
    //启动Bundle
    void start() throws BundleException;
    //停止Bundle
    void stop(int var1) throws BundleException;
    //停止Bundle
    void stop() throws BundleException;
    //更新Bundle
    void update(InputStream var1) throws BundleException;
    //更新Bundle
    void update() throws BundleException;
    //卸载Bundle
    void uninstall() throws BundleException;
    //获取Bundle元数据
    Dictionary<String, String> getHeaders();
    //获取BundleId
    long getBundleId();
    //获取Bundle地址
    String getLocation();
    //获取Bundle元数据
    Dictionary<String, String> getHeaders(String var1);
    //获取Bundle_SymbolicName
    String getSymbolicName();
    //获取Bundle私有空间下的文件
    File getDataFile(String var1);
}
 

 

Bundle对象的唯一标识

 

OSGI规范中有三种方式可以唯一确定一个Bundle

1、在“模块层”元数据中定义的Bundle-SymbolicNameBundle-Version。这个属于静态的 Bundle jar文件识别。

2Bundle在被首次加载时,需要调用BundleContextinstallBundle方法,该方法需要一个Bundle jar所在的地址。通过这个地址可以唯一识别一个已经安装的Bundle对象。在BundleContext中定义了一个根据地址获取Bundle对象的方法:Bundle getBundle(String var1);

3、每个已经安装的Bundle会生成一个bundleId,这个id是从0开始安装Bundle的安装顺序自增的。在OSGI框架中可以通过这个bundleId唯一确定一个Bundle对象。在BundleContext定义了一个根据id获取Bundle对象的方法:Bundle getBundle(long var1);

 

bundleId0Bundle对象是OSGI框架运行时加载的第一个Bundle,也称为系统Bundle”,它随框架的启动而自动加载。当系统Bundle对象停止时,它会首先停止其它所有的Bundle,然后在关闭自己。

 

一个Bundle的生命周期

 

上一节列出了OSGI规范中定义的生命周期层常用的API方法,具体这些方法是如何使用,以及如何控制Bundle的生命周期的呢?这里以摘自《OSGI实战》中的生命周期状态图为例把各个API方法串联起来:



 

 

这个图中描述了一些Bundle的状态,在上图中以椭圆形表示,这些状态值都是在Bundle接口中定义的常量(见上一节);另外状态的转换需要有的需要调用一些方法完成,对应图中的箭头线,有些是框架自己隐式的完成,有些需要调用前一节中提到的生命周期方法才能完成。没有箭头线相连的状态 表示两者之间不能直接到达。下面一步步的来看这些生命周期方法:

 

1、安装方法:BundleContext. installBundle()系列方法,参数可以是一个jar包的路径,也可以是一个输入流。调用该方法,可以向框架中安装一个Bundle,此时会生成一个Bundle对象,状态为INSTALLED(已安装)。

 

2、启动方法:Bundle.start()方法,该方法的调用有一个前提,就是Bundle的已解析(RESOLVED),解析的过程是由框架自己隐式的完成。该方法调用成功后Bundle会进入激活状态(ACTIVE),如果失败回退到已解析状态,这也是有框架隐式的完成状态转换。

3、停止方法:Bundle.stop方法,这个方法会触发Bundle经“停止中”状态 回退到已解析状态。

5、更新方法:Bundle.update方法,最终状态会转到已安装,也就是在启动时需要重新解析。

6、卸载方法:Bundle.uninstall方法,可以让一个处于“已安装”的状态转换为卸载状态。如果该Bundle正处于激活状态,OSGI框架会自己调用stop方法停止该Bundle转换为已解析状态,再隐式的转换为已安装状态,最后执行卸载操作,状态变为卸载状态

 

 

 

猜你喜欢

转载自moon-walker.iteye.com/blog/2408333