OSGI原由

    软件的复杂度总是越来越高,为了解决人有限的处理能力和它之间的矛盾,就要用到“内聚”,也就是说将“复杂度”封装起来,只暴露出少量必要的部分。

    例如:高低电平信号->机器码->汇编指令->高级语言语句->函数(function或method)->类(class)->包(package) 就是一个复杂度封装的过程,就是一个“内聚”的过程。

    模块化也是一种更高层面的“内聚”,从java和osgi的角度看,模块化是在包(package)的层面上,更进一步“封装”。

    封装主要需要解决两个问题,一个是“隔离”,一个是“暴露”。

    那么osgi是怎么样解决这两个问题的呢?
    osgi是在jvm的classloader的机制层面上来实现模块化层面的封装。

    一、osgi如何实现模块间的“隔离“?
    jvm包括Bootstrap、Extension、Application和Custom四类Classloader,这4类Classloader之间存在父子关系。这些Classloader采用双亲委托模型(Parent Delegation Mode)实现Class的加载。也就是当一个Class要引用另一个Class时,会先在加载自己的Classloader查找是否有所需的类,否则就委托其父Classloader,一直到Bootstrap Classloader,直到查找到该Class为止,如果直到Bootstrap Classloader都没找到所需的Class,就由本级的Classloader尝试加载该Class,如果加载失败,则抛出ClassNotFound Exception。

    一般来说,在传统的java应用中,除了一些有特殊目的的应用外,通常会有Bootstrap、Extension和Application三个Classloader,应用中的类大部分都会由一个Application Classloader来加载,即使这些类是分布在不同的jar包里,所以在运行时,同一个应用中,不同jar包就可以很方便地通过这个Application Classloader互相引用彼此的类。

    而osgi则是通过在jar包里添加/META-INF/manifest.mf文件,成为一个bundle(所以bundle本质还是一个jar包),这些bundle就是osgi的模块化的具体表现。在运行时,osgi平台将加载这些bundle,而且每个bundle都使用独立的Classloader来加载其中的类。

    从Classloader的双亲委托模型可以看到某个类并不能被其Classloader的“兄弟”Classloader查找到。所以osgi正是利用这个特点,将每个bundle隔离开来,使bundle之间不能互相存取对方的类,这样就达到了模块间的“隔离”的目的。

    二、osgi如何让模块“暴露”出必要的类?
    模块与模块之间会有“耦合”的需要,也就是互相引用/调用彼此的服务的需要。而需要被其它模块引用/调用的服务部分,就需要“暴露”出去。

    在osgi的语境下,模块是通过Export Packages的方式来输出需“暴露”的Packages(这里如果翻译成“包”,和jar包之类的概念有冲突),具体做法就是在/META-INF/mainifest.mf里添加Export-Packages项,将需要输出的Packages列出来,如果有多项,可以用逗号分隔开来,而且可以对这些Packages指明版本号。

    从Classloader的角度看,Export Package则是将需输出的Packages委托其父Classloader来加载,而通常osgi的实现都是用同一个Classloader作为加载bundle的Classloader的父Classloader,所以委托父Classloader来加载,就可以被其他bundle的classloader“查找”到这些输出的Packages。

   

猜你喜欢

转载自killko.iteye.com/blog/1683474
今日推荐