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),由于jboss从7开始采用模块化的类加载模式,因此,首先把第三方jar做成module,然后在JBoss目录/standalone/configuration/standalone.xml中,在<subsystem xmlns="urn:jboss:domain:osgi:1.2" activation="eager"> <properties>目录下添加

<property name="org.jboss.osgi.system.modules.extra">
    org.apache.hadoop,org.apache.hbase
</property>

<property name="org.osgi.framework.system.packages.extra">
     org.apache.hadoop.conf,org.apache.hadoop.hbase,org.apache.hadoop.hbase.client,org.apache.hadoop.hbase.util
</property>

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

Imported Packages
org.apache.hadoop.conf,version=0.0.0 from system.bundle (0)
org.apache.hadoop.hbase,version=0.0.0 from system.bundle (0)
org.apache.hadoop.hbase.client,version=0.0.0 from system.bundle (0)
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页面中可以看到:

Imported Packages
org.apache.hadoop.conf,version=0.0.0 from hadoop-core-0.20.2 (16)
org.apache.hadoop.hbase,version=0.0.0 from hbase-0.94.2 (17)
org.apache.hadoop.hbase.client,version=0.0.0 from hbase-0.94.2 (17)
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 xxx.jar 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可以为:

<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">
  <!--
/**
 *Author: bs
 */
-->
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.apache.hboop</groupId>
  <artifactId>hadoop-core</artifactId>
  <packaging>bundle</packaging>
  <name>dong</name>
  <version>1.0</version>
  <description>
    ...
  </description>
  <dependencies>
    <dependency>
	<groupId>org.osgi</groupId>
	<artifactId>osgi_R4_core</artifactId>
	<version>1.0</version>
	<optional>true</optional>
	<scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.osgi</groupId>
	<artifactId>osgi_R4_compendium</artifactId>
	<version>1.0</version>
	<optional>true</optional>
	<scope>provided</scope>
    </dependency>
    <dependency>
	<groupId>org.apache.hadoop</groupId>
	<artifactId>hadoop-core</artifactId>
	<version>1.1.0</version>
    </dependency>
  </dependencies>
  <build>
    <directory>${basedir}/bundles</directory>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>1.4.3</version>
        <extensions>true</extensions>
        <executions>
           <execution>
              <id>wrap-my-dependency</id>
              <goals>
                <goal>bundleall</goal>
              </goals>
              <configuration>
                <wrapImportPackage>*</wrapImportPackage>
              </configuration>
           </execution>
         </executions>
      </plugin>
    </plugins>
  </build>
</project>

maven运行时的Goals设置为org.apache.felix:maven-bundle-plugin:bundleall,最后生成的bundle在bundles/classes目录下,这个目录可以通过

<directory>${basedir}/bundles</directory>
设置。

<goal>设置为buildall会将所有用到的依赖jar也打包成bundle,另外还有bundle, wrap等goal


3> 将jar包打进bundle

   如果在编译的过程中,以Maven build为例,注意没有<scope>provided</scope>

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-core</artifactId>
    <version>0.20.2</version>
</dependency>

这种方法要格外小心import与export的设置,因为如果采用默认方式的话,很有可能会把引用的这个jar里所有的包都export,由此引起类的依赖传递很麻烦,当然也可以结合maven-bundle-plugin做一些设置








  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值