模块层是OSGi框架的最基础层次,是OSGi其他部分的基础。
一个从逻辑上封装实现类的集合,一个基于实现类子集的可选公共API,一个对外部代码依赖关系的集合。
package是Java提供的一种内建的模块化方式,但它有一些限制:http://blog.csdn.net/vking_wang/article/details/9735395
以上讨论的都是“逻辑模块化”;而对应的“物理模块化”,指的是代码如何封装和部署,例如部署为多个jar。
高内聚,一个模块专注于单个关注点;
低耦合,模块间耦合度低。
定义:
bundle是一个模块化的物理单元,以jar文件的形式包含代码、资源、元数据。其中jar文件的边界也作为执行时逻辑模块化的封装边界。
理论上,元数据也可以保存到类本身(类似annotation),而不是物理模块。这样的优点是更容易看出元数据与代码之间的关系。
而把元数据保存到一个独立文件则更加灵活:
为bundle内部的类赋予不同于外部代码的可见性规则;在bundle JAR中的public类不必对外部可见!
bundle元数据定义在META-INFO/MANIFEST.MF文件中,包含以下几个部分:
可选的描述信息,只为帮助人们理解。
当某个bundle类需要位于同一bundle的另一个类时,为了找出这个类,需要搜索包含该bundle的所有bundle类路径。
使用Bundle类路径,你可以指定一个bundle内部的路径列表,类加载器从这个列表里查找类或资源。
【例】
Bundle-ClassPath: .,other-classes/,embedded.jar
上例中,bundle首先搜索相对于根的包;然后搜索other-classes文件夹;最后是bundle的内嵌jar文件。
如果不指定Bundle-ClassPath,框架提供的默认值是点号(.),这样bundle JAR就和标准JAR具有相同的默认内部搜索策略。
Export-Package指定了bundle暴露给其他bundle的包。
【例】
Export-Package: org.foo.shape
OSGi默认是什么都不公开的。
OSGi在包层次定义bundle间的共享。
在指定Export-Package时,可以同时使用“属性”来进行区分。
——作用1:如果不同的bundle导出的包名相同,可以以此区分。
Export-Package: org.foo.shape; vendor="Alpha"
——作用2:版本管理
Export-Package: org.foo.shape; version="2.0.0"version 默认值是“0.0.0”
※ 这说明:OSGi不但支持bundle版本化,而且支持包版本化。
※ 导出包中的属性,只有当导入包也指定了这些属性时,才有效。否则会被忽略。
OSGi要求所有的bundle显式声明依赖外部代码。
【例】
Import-Package: org.foo.shape, org.foo.other
导入包时,可以用导出属性作为匹配属性。——属性 的作用像是一个过滤器。
Import-Package: org.foo.shape; version="2.0.0"注意,上例的version表示导入版本号 从2.0.0到无穷。
如果要指定一个精确版本号,应该用:version="[2.0.0, 2.0.0]"
version的默认值是“0.0.0”,表示版本号从0.0.0到无穷。
其他需要注意的:
OSGi使用包级粒度来表达bundle直接的依赖关系,而不是模块级。
模块级的依赖是脆弱的,例如bundle随着时间推移越来越庞大,可能会拆分成多个bundle;如果使用模块级依赖就会破坏现有客户端。
OSGi框架通过以下顺序搜索一个类:
问题1:一个标准JAR能否在不做任何改动的情况下作为bundle JAR使用,安装到OSGi框架中?
——能。但是没有任何意义,因为标准JAR默认导出包时空的,即不对外公开任何内容!
问题2:一个bundle JAR能否在OSGi环境以外作为一个标准JAR使用?
——只有Bundle-ClassPath为点号的bundle JAR才可以!否则bundle JAR可能会依赖其中的某个文件夹,或者嵌入JAR,放到OSGi环境之外会导致找不到类。