【OSGi】2. bundle与模块化

模块层是OSGi框架的最基础层次,是OSGi其他部分的基础。


1、模块

定义:

一个从逻辑上封装实现类的集合,一个基于实现类子集的可选公共API,一个对外部代码依赖关系的集合。

package是Java提供的一种内建的模块化方式,但它有一些限制:http://blog.csdn.net/vking_wang/article/details/9735395

以上讨论的都是“逻辑模块化”;而对应的“物理模块化”,指的是代码如何封装和部署,例如部署为多个jar。

作用:

高内聚,一个模块专注于单个关注点;

低耦合,模块间耦合度低。


2、bundle

定义:

bundle是一个模块化的物理单元,以jar文件的形式包含代码、资源、元数据。其中jar文件的边界也作为执行时逻辑模块化的封装边界。

2.1 bundle在物理模块化中的作用

  1. 确定模块的成员关系;——如果一个类包含在bundle JAR文件中,那么它就是bundle的成员。灵活。
  2. 作为部署单元使用;
  3. bundle JAR文件是bundle元数据的容器;——用Jar清单文件MANIFEST.MF来存储bundle元数据

理论上,元数据也可以保存到类本身(类似annotation),而不是物理模块。这样的优点是更容易看出元数据与代码之间的关系。

而把元数据保存到一个独立文件则更加灵活:

  • 不必为修改元数据而重新编译bundle;
  • 不必访问源代码就可以编辑元数据;——处理遗留库,或第三方库时方便
  • 不必将类加载到JVM就可以访问元数据;
  • 对OSGi没有编译时依赖;
  • 可以在多个模块中使用相同的代码;
  • 可以在不支持annotation的JVM中使用。

2.2 bundle在逻辑模块化中的作用

  1. 逻辑地封装成员类;

为bundle内部的类赋予不同于外部代码的可见性规则;在bundle JAR中的public类不必对外部可见!


3、元数据MANIFEST.MF

bundle元数据定义在META-INFO/MANIFEST.MF文件中,包含以下几个部分:

3.1 可读信息

可选的描述信息,只为帮助人们理解。

  • Bundle-Name

  • Bundle-Vendor

  • Bundle-Copyright

  • ……

3.2 bundle标识

  • Bundle-SymbolicName

    ——为何不用Bundle-Name?由于历史原因。OSGi早期版本并不要求唯一标识bundle,提供的Bundle-Name纯粹是为了提供信息
  • Bundle-Version

  • Bundle-ManifestVersion: 2

    ——为了维护R4规范以前创建的遗留bundle的向后兼容性而引入。有Bundle-ManifestVersion的,就要求必须被唯一地标识。

3.3 代码可见性

  • Bundle-ClassPath

当某个bundle类需要位于同一bundle的另一个类时,为了找出这个类,需要搜索包含该bundle的所有bundle类路径。

使用Bundle类路径,你可以指定一个bundle内部的路径列表,类加载器从这个列表里查找类或资源。

【例】

Bundle-ClassPath: .,other-classes/,embedded.jar

上例中,bundle首先搜索相对于根的包;然后搜索other-classes文件夹;最后是bundle的内嵌jar文件。

如果不指定Bundle-ClassPath,框架提供的默认值是点号(.),这样bundle JAR就和标准JAR具有相同的默认内部搜索策略。

  • Export-Package

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版本化,而且支持包版本化

※ 导出包中的属性,只有当导入包也指定了这些属性时,才有效。否则会被忽略。

  • Import-Package

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到无穷。


4、扩展

其他需要注意的:

4.1 依赖粒度、导出粒度

OSGi使用包级粒度来表达bundle直接的依赖关系,而不是模块级

  1. 模块级依赖是依赖指定模块(依赖谁);
  2. 包级依赖是依赖哪些包(依赖什么);

模块级的依赖是脆弱的,例如bundle随着时间推移越来越庞大,可能会拆分成多个bundle;如果使用模块级依赖就会破坏现有客户端。

4.2 类搜索顺序

OSGi框架通过以下顺序搜索一个类:

  1. 如果类以java.开头,则当前类加载器的父类加载器会去搜索这个类。如果没找到,则该搜索以异常结束;
    ——保证所有bundle使用相同的核心Java类。
  2. 如果类是bundle导入包中的类,则从导入bundle中搜索这个类。如果没找到,则该搜索以异常结束;
    ——保证导入包不会被分割到导入bundle和导出bundle中。——?
  3. 从bundle类路径中搜索类。如果没找到,则该搜索以异常结束;

4.3 Bundle JAR和标准JAR能否互换使用?

问题1:一个标准JAR能否在不做任何改动的情况下作为bundle JAR使用,安装到OSGi框架中?

——能。但是没有任何意义,因为标准JAR默认导出包时空的,即不对外公开任何内容!

问题2:一个bundle JAR能否在OSGi环境以外作为一个标准JAR使用?

——只有Bundle-ClassPath为点号的bundle JAR才可以!否则bundle JAR可能会依赖其中的某个文件夹,或者嵌入JAR,放到OSGi环境之外会导致找不到类。






你可能感兴趣的:(Bundle,osgi)