OSGI加载第三方非bundle化jar包的几种方式

以下皆以felix osgi + JBoss7为例。

osgi运行期类加载按照以下顺序进行:

1>对于以java.开头的package,用父加载器,即启动osgi framework的类加载器,如果找不到类,报exception

2>如果依赖的类是Import-Package中某个package定义的类,那么osgi framework将从Export这个package的bundle中加载类,如果在这个bundle中找不到这个类,报exception

3>搜索bundle class path(由Bundle-ClassPath所指定的类路径,例如:Bundle-ClassPath: .,other-classes/,embedded.jar, 关于Bundle-ClassPath在OSGI in Action中有详细解释如下), 找不到,报exception

“
This tells the OSGi framework where to search inside the bundle for classes. The period(.) signifies the bundle JAR file, For this example, 
the bundle is searched first for root-relative packages, then in the folder called other-classes, and finally in the embedded JAR in the bundle. 
The framework supplies a default value of period (.). 
”

因此,如果bundle用到了第三方没有被bundle化的jar包,那么只有三种方式可以加载:

1> 通过父加载器加载(system bundle中export)

2> 将jar转换成bundle,并且export需要的package

3> 将jar打包进引用方bundle

具体实现方式

1> 父加载器

    这又有两种实现方式

    方式一:利用org.osgi.framework.system.packages.extra

     这个property的具体解释如下,原文参见 http://felix.apache.org/site/apache-felix-framework-configuration-properties.html:

     org.osgi.framework.system.packages.extra - Specifies a comma-delimited list of packages that should be exported via the System Bundle from the framework class loader in addition to the packages inorg.osgi.framework.system.packages. The default value is empty. If a value is specified, it is appended to the list of default or specified packages inorg.osgi.framework.system.packages.

因此,首先将待加载的类添加到CLASSPATH,例如,我们的项目中需要hadoop与hbase的几个package(org.apache.hadoop.conf, org.apache.hadoop.hbase, org.apache.hadoop.hbase.client, org.apache.hadoop.hbase.util),那么设置$HOME目录下.bash_profile中的内容如下:

查看文本 打印 ?
  1. JAVA_HOME=/YourJDKHome  
  2. export JAVA_HOME  
  3. CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:/opt/hadoop-core-0.20.2.jar:/opt/hbase-0.94.2.jar  
  4. export CLASSPATH  

然后source .bash_profile使配置生效,然后在JBoss目录/standalone/configuration/standalone.xml中,在 目录下添加

查看文本 打印 ?
  1. <property name="org.osgi.framework.system.packages.extra">  
  2.      org.apache.hadoop.conf,org.apache.hadoop.hbase,org.apache.hadoop.hbase.client,org.apache.hadoop.hbase.util  
  3. property>  

重启,Jboss, 可以发现所需要的package都已经正确解析,如果standalone.xml配置好了bundle的启动,那么在Jboss的bundle console页面中可以看到:

查看文本 打印 ?
  1. Imported Packages  
  2. org.apache.hadoop.conf,version=0.0.0 from system.bundle (0)  
  3. org.apache.hadoop.hbase,version=0.0.0 from system.bundle (0)  
  4. org.apache.hadoop.hbase.client,version=0.0.0 from system.bundle (0)  
  5. org.apache.hadoop.hbase.util,version=0.0.0 from system.bundle (0)  

      方式 二: org.osgi.framework.bootdelegation

     org.osgi.framework.bootdelegation - Specifies a comma-delimited list of packages that should be made implicitly available to all bundles from the parent class loader. It is recommended not to use this property since it breaks modularity. The default value is empty.


2> 将jar转换成bundle,并且export需要的package

      方式1:利用eclipse的BndTools插件,安装参见http://bndtools.org/installation.html

      安装完了以后,选择"File" -> "New" -> "Other...",选择Bndtools->Wrap JAR as OSGi Bundle project, 添加待转换的jar,选择要export的package,生成工程以后可以手动修改bnd.bnd文件,比如Import-Package, Export-Package等等,

在"Contents"选项卡里可以看到"Export Packages"以及"Caculated Imports",如果后者为空,但实际上确实有依赖,可以关闭eclipse重新打开,应该就可以看到。


完了以后点击"Build"选项卡的"Rebuild Project",然后在工程的"generated"目录下可以生成转换后的jar


      

将这个转换后的jar部署到osgi framework, 其他bundle就可以用它export出去的package, 有一个需要注意的问题就是,在转换的过程中,bnd tool会自动分析出这个待转换jar需要import的package, 因此默认情况下在转换后的jar里面的META-INF/MANIFEST.MF中会有这些记录,这些记录意味着osgi framework必须提供这些相应的pacakge,对于认为运行期不需要的package,可以通过bnd tool在Import-Package中通过!+package名加以禁止,如果standalone.xml配置好了bundle的启动,那么在Jboss的bundle console页面中可以看到:

查看文本 打印 ?
  1. Imported Packages  
  2. org.apache.hadoop.conf,version=0.0.0 from hadoop-core-0.20.2 (16)  
  3. org.apache.hadoop.hbase,version=0.0.0 from hbase-0.94.2 (17)  
  4. org.apache.hadoop.hbase.client,version=0.0.0 from hbase-0.94.2 (17)  
  5. org.apache.hadoop.hbase.util,version=0.0.0 from hbase-0.94.2 (17)  

     方式2:直接通过jar命令

     如果可以明确bundle的依赖关系(可以通过bnd tool获得),并且生成了正确的MANIFEST.MF,那么可以通过jar命令打包,比如目录结构如下:

     sun

      |__ dong.jar

      |__ MANIFEST.MF

      在MANIFEST.MF除了设置好import与export的package以外,还要设置好Bundle-ClassPath: .,dong.jar

      然后通过命令jar cfm MANIFEST.MF dong.jar 打包,如果想拆包检查的话,可以用jd-gui等反编译工具

      方式1和方式2结合起来用会比较方便,如果想在jar中抽出一部分打bundle,可以通过bnd tool来做,即使不做抽取,bnd tool生成的也是package级的,如果想把jar以.jar的形式整个打进bundle,可以先通过bund tool生成MANIFEST.MF,然后通过jar命令完成打包


    方式3:利用Maven的maven-bundle-plugin ,具体参见http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html

   例如,pom.xml可以为:

查看文本 打印 ?
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  2.   

你可能感兴趣的:(osgi)