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 的生命周期


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM