zoukankan      html  css  js  c++  java
  • OSGi 系列(三)之 bundle 详解

    OSGi 系列(三)之 bundle 详解

    1. 什么是 bundle

    bundle 是以 jar 包形式存在的一个模块化物理单元,里面包含了代码,资源文件和元数据(metadata),并且 jar 包的物理边界也同时是运行时逻辑模块的封装边界。

    图3.1 bundle组成

    2. MANIFEST.MF 规范

    • 位置:META-NF/MANIFEST.MF

    • 文件格式

      1. 属性声明的一般格式是 name: value
      2. 一行不超过 72 个字符,下一行则由单个空格字符开始

    3. bundle 常用标识符

    标识符 说明
    Bundle-Category 描述用逗号分隔的分类名称
    Bundle-Activator 启动和停止 bundle 的类名称
    Bundle-Classpath 定义用逗号分隔的路径,包含的内容有 JAR 文件和包含类和资源的目录(bundle内部) .点号代表 JAR 文件的根目录,同时也是默认的
    Bundle-Copyright 描述 bundle 的版权信息
    Bundle-Description 对 bundle 的描述信息
    Bundle-Localization 描述 bundle 的本地文件地址,默认值是 OSGI-INF/l10n/bundle
    Bundle-ManifestVers on
    Bundle-Name 定义了一个具有可读性的名字来标识 bundle。应该是一个简短易读没有空格的名
    bundle-SymbolicName (必须)提供了 bundle 的一个全局的惟一的标志符
    Bundle-UpdateLocation 描述 bundle 的更新地址。bundle 需要更新,则使用这个地址进行更新。
    Bundle-Vendor 描述 bundle 的发行者信息。
    Bundle-Version 描述 bundle 的版本信息。默认值为0.0.0
    DynamicImport-Package 包含了一个逗号分隔的动态导入包清单
    Export-Package 导出包声明
    Import-Package 声明 bundle 导入的包
    Require-Bundle 指定 bundle 中需要其他 bundle 导出的内容

    3.1 Bundle-SymbolicName

    Bundle-SymbolicName(符号名称) 是唯一必须指定的。通过 bundle 的符号名称和版本号可以在框架中惟一的确定一个 bundle。也就是说,如果一个 bundle 和另外一个 bundle 有着同样的符号名称和版本号,那么这两个 bundle 就是等价的。

    Bundle-Name 是给用户读的,而 Bundle-Symbolicname 是给 OSGi 框架读的,让 OSGi 框架能够唯一标识一个 bundle。

    示例:

    Bundle-SymbolicName: com.edu.osgi.hellowrod
    

    3.2 Bundle-Version

    格式:主版本号(Major) + 副版本号(Minor) + 微版本号(Micro) + 限定符串(Qualifier)

    bundle-version: 1.0.0.bate1
    
    • 默认值为:0.0.0
    • 主版本号、副版本号、微版本号必须是数字
    • 限定字符串可以为空,默认为空
    • 版本号是可以进行比较的,比较是根据主版本号、小版本号、微版本号的顺序进行比较。最后是字符串的限定符比较。eg:1.0.0.2016213 > 1.0.0

    3.3 Export-Package

    标准的 jar 文件默认公开一切内容,而 bundles 默认不公开任何内容 OSGi 通过 Export-Package 公开内容

    • 可以导出多个包,多个用逗号隔开

    • 可以给导出包增加任何属性,以区分导出包

    • 导出的包 version 默认为 0.0.0

      Export-Package: com.edu.api
      Export-Package: com.edu.api;version="1.0.0"
      Export-Package: com.edu.api,com.edu.util;version="1.0.0"
      
    • 当导出一个包的时候,默认导出该包的所有类、接口。可以设置过滤条件:include 包含;exclude 排除

      Export-Package: com.edu.api;include:="*Service"
      Export-Package: com.edu.api;exclude:="*Impl"
      

    3.4 Import-Package

    OSGi 要求 bundle 显示声明对外部代码的依赖:

    • 不能导入 java.*

    • 导入一个包,不会导入它的子包

    • 通过增加属性导入特定的包

      Import-Package: com.edu.api
      Import-Package: com.edu.api;version="1.0.0"
      
    • Import-Package 版本过滤:

      语法 含义
      [min,max) min<=x<max
      [min,max] min<=x<=max
      (min,max] min<x<=max
      (min,max) min<x<max
      min min<=x
      [1.0.0,1.0.0] 精确指定一个版本
      Import-Package: com.edu.api;version="[1.0.0,2.0.0)"
      Import-Package: com.edu.api;version="1.0.0"
      
    • Import-Package 属性过滤:

      Import-Package: com.edu.api;type="apache"

      默认情况下 bundle2 虽然没有声明自定义属性 type,但在默认情况下这并不会产生匹配冲突。如果要改变这种情况,可以使用 mandatory 附加参数,强制要求必须存在扩展属性オ能成功匹配。

      # bundle1
      Import-Package: com.edu.api;type="1";mandatory:="type"
      # bundle2
      Export-Package: com.edu.api
      Export-Package: com.edu.api;type="1"
      

      注意: type 是属性;mandatory 是 OSGi 的指令,指令前必须加 ":"

    • Import-Package 可选导入:

      在大多数情况下,导入某个 Package,就说明当前这个 bundle 的正常运行是必须依赖导入的 Package 的。但还有另外一些场景导入某个 Package 是为了实现一些不影响 Bundle 正常运行的附加功能,比如 Apache thrift 里面会用到 httpclient。但是只是在特殊情況下才会用到,此时就不需要强行依赖 httpclient 了。

        # resolution 可选值 mandatory(默认) 和 optional
        Import-Package: com.edu.api;resolution:="optional"
      

    3.5 DynamicImport-Package

    定义需要动态导入的包。这部分定义没有在 bundle 解析过程中使用,而是在运行时动态解析并加载共享包。

    动态导入和可选导入实现的功能有些类似,它们的共同特征是在 bundle 解析期间即使找不到要导入的依赖,也不会导致解析失败。它们的区别是,动态导入每次加载包中的类都会尝试去查找动态导入包,而可选导入包只有在 bundle 解析时才进行连接尝试

    DynamicImport-Package: *
    DynamicImport-Package: com.edu.*;type=1
    

    不推荐使用,尽量用 Import-Package。

    3.6 Bundle-Classpath

    Bundle-Classpath 标记有默认值 ".",它代表该 bundle 的根目录,或者说代表该 Bundle 的 JAR 文件

    • 可以设置多个,多个用逗号隔开

    • 一旦定义了 Bundle-Classpath 就需要显示加入 "."

    • 按照声明的顺序搜索 bundle 类路径条目

      Bundle-Classpath: .,lib/xxx.jar

    一般用于非 bundle 包的引用,不推荐使用,违反了 bundle 的使用原则。

    4. 系统 bundle

    • 系统 bundle 的 bundle ID 为 0
    • 系统 bundle 的 getLocation() 返回的是字符串 "System Bundle"
    • BundleContex.getBundle(0) 或 BundleContex.get("SystemBundle") 方法中获取到系统 bundle 的对象实例
    • 系统 bundle 的启动级别固定为 0,且不能修改

    5. bundle 依赖的常见错误

    1. java.lang.ClassNotFoundException

      bundle 没有导入相应的包,或有导入,但被 include/exclude 限制

    2. org.osgi.framework.BundleException: Unable to resolvecom.edu.osgi bank

      bundle 有导入,但没有其它的 bundle 导出该包

    6. bundle 生成插件

    6.1 maven-jar-plugin

    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <archive>
            <manifestEntries>
                <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
                <Bundle-SymbolicName>com.github.binarylei.demo-osgi</Bundle-SymbolicName>
                <Bundle-Version>1.0.0</Bundle-Version>
                <Import-Package>org.osgi.framework</Import-Package>
                <Bundle-Activator>com.github.binarylei.HelloBundleActivator</Bundle-Activator>
            </manifestEntries>
        </archive>
    </configuration>
    </plugin>
    

    6.2 maven-bundle-plugin

    7. bundle 的生命周期

  • 相关阅读:
    The .NET weak event pattern in C#
    Setting an Event to Null
    Android: INSTALL_FAILED_UPDATE_INCOMPATIBLE错误解决措施
    快速打开 Mac OS X 隐藏的用户资源库文件夹
    Complete uninstall on Mac, HELP!
    为什么MacBook装Windows这么火?
    mac 刻录ISO系统盘
    MySQL子查询慢现象的解决
    程序人生的四个象限和两条主线
    Xamarin.Android,Xamarin.iOS, Linking
  • 原文地址:https://www.cnblogs.com/binarylei/p/8537307.html
Copyright © 2011-2022 走看看