先让我们来看看OSGi service platform的体系结构。另外要说明的是,我在后面的文章中,将采用framework来代替OSGi service platfrom,这样比较简便。 下面这张图来自OSGi Alliance的主页(http://www.osgi.org/)
层次很分明吧。放到我们假想的案例中,OS&Hardware可以对应为PDA的硬件和操作系统,您可以想象它是Intel xscacle + Microsoft window mobile,或者是Arm + embedded Linux 而Execution Environment当然是我们上次提到的CVM + CDC + FP + PP,有这个jvm的配置运行framework就绰绰有余了。而再往上,就是我们要重点学习和分析的OSGi framework了。而Modules, Life Cycle, Service Registry, Services和Security是从不同的5个角度来划分framework所具备的功能,后面我将会从除了Security外的四个方面分别结合我们的假设场景来分析。而体系结构的最上层是符合OSGi framework接口标准的应用程序,也就是OSGi世界中有名的“bundle”。
下面来看看OSGi规范是如何定义一个bundle的。在r4规范的第27页中大致这样描述到:Framework定义了模块(modularization)的单元,叫作bundle。Bundle实际就是一个具有jar(Java ARchive)格式的文件,其中包含了java的class文件和其他资源文件(比如图标,配置文件等等)。Bundle可以在自己的manifest文件中说明自己能够提供哪些java包,其他bundle如果在自己的manifest文件中指定了它需要这个包,那他们之间就可能产生java包的依赖关系,这样多个bundle之间就可以共享java包。值得注意的是,bundle是能够在framework中部署的唯一格式。下面给出原文的描述: A bundle is a JAR file that: ? Contains the resources necessary to provide some functionality. These resources may be class files for the Java programming language, as well as other data such as HTML files, help files, icons, and so on. A bundle JAR file can also embed additional JAR files that are available as resources and classes. This is however not recursive. ? Contains a manifest file describing the contents of the JAR file and providing information about the bundle. This file uses headers to specify information that the Framework needs to install correctly and activate a bundle. For example, it states dependencies on other resources, such as Java packages, that must be available to the bundle before it can run. ? Can contain optional documentation in the OSGI-OPT directory of the JAR file or one of its sub-directories. Any information in this directory is optional. For example, the OSGI-OPT directory is useful to store the source code of a bundle. Management systems may remove this information to save storage space in the OSGi Service Platform.
framework的modules这一方面功能将主要负责bundle的安装部署,更新和卸载,以及bundle在设备的物理存储(如果有的话)。在这个层次,每个bundle都是独立的,它的安装,升级和卸载完全不依赖任何其他bundle,这点framework提供了强大的隔离性。Life Cycle专门负责对bundle的解析(比如关联两个有相互依赖关系的bundle),启动(相当于运行应用程序)和停止(相当于停止应用程序)。这个层次中,bundle间的逻辑关系被创建起来,这些关系能否成功的创建,将会直接影响bundle的成功解析和启动。Service Registry可以认为是一个数据库,bundle启动后,可以向这个数据库注册它动态提供的服务。只要bundle不被停止,且bundle不主动撤销注册的服务,这个服务将一直保存在这个数据库中供其它bundle来查询和使用。而Services就是由bundle运行时提供的具体服务对象,这些服务对象的存在,使得framework具有极其动态的特征,并为framework运行时提供灵活强大的功能。 另外,根据OSGi Alliance的说法,OSGi的运行平台包括了j2me(kvm + cldc + midp, cvm + cdc+fp), j2se, j2ee。不过,我个人还是觉得目前的midp规范还太弱,OSGi要想运行在上面,很多功能实现起来都比较不爽。
好,有了对framework结构层次的皮毛认识,下面我们就开始着手改造那个“扶贫助手”的程序,使其变成OSGi的bundle(s),然后从上面提到的4个方面来分析framework的机制。 这里,我先给出“扶贫助手”的java application模拟程序代码:
package aa.bb.cc;
public class FamilyInfo { private String familyName; //家庭名称 private int population; //人口数量 private int incomePerYear; //家庭年收入
…..//省略了getter和setter方法
//获得家庭人均年收入 public int getIncomePerMember(){ return (int)(this.incomePerYear/this.population); }
public String toString() { return "Family: " + this.familyName + ", population: " + this.population + ", income: " + this.incomePerYear; } //按家庭年收入又低到高排序 public static void sortByIncomePerYear(FamilyInfo[] families){ FamilyInfo temp = null; for(int i = 0; i < families.length -1; i ++){ for(int j = i + 1; j < families.length; j ++){ if(families[i].getIncomePerYear() > families[j].getIncomePerYear()){ temp = families[i]; families[i] = families[j]; families[j] = temp; } } } }
//按家庭人均年收入由低到高排序 public static void sortByIncomePerMember(FamilyInfo[] families){ FamilyInfo temp = null; for(int i = 0; i < families.length -1; i ++){ for(int j = i + 1; j < families.length; j ++){ if(families[i].getIncomePerMember() > families[j].getIncomePerMember()){ temp = families[i]; families[i] = families[j]; families[j] = temp; } } } }
public static void main(String[] args){ FamilyInfo[] families = new FamilyInfo[3]; families[0] = new FamilyInfo(); families[0].setFamilyName("Zhang"); families[0].setPopulation(3); families[0].setIncomePerYear(1200); families[1] = new FamilyInfo(); families[1].setFamilyName("Li"); families[1].setPopulation(6); families[1].setIncomePerYear(1800); families[2] = new FamilyInfo(); families[2].setFamilyName("Liu"); families[2].setPopulation(4); families[2].setIncomePerYear(1500); FamilyInfo.sortByIncomePerYear(families); for(int i = 0; i < families.length; i ++){ System.out.println(families[i].toString()); } FamilyInfo.sortByIncomePerMember(families); for(int i = 0; i < families.length; i ++){ System.out.println(families[i].toString()); } } }
|