前言
前一篇文章中使用idea开发工具,并集成equinox框架展示了一个简单的OSGI多bundle搭建的demo。文中提到使用idea插件可以实现对bundle元数据的自动生成(默认方式)。其实本质上idea自动的OSGI插件默认使用了bnd工具。
bundle jar与普通jar包的最直接的区别就是bundle jar包含一个元数据文件MANIFEST.MF。在开发OSGI模块过程中,最频繁的工作就是把自己开发的jar包封装成bundle,或者把一些第三方jar包封装成bundle,也就是如何去生成一个元数据文件MANIFEST.MF。最直接的方式就是,手工创建这个文件并放到jar包中。
但每次手工创建或修改元数据文件,然后再塞到jar包中是件很繁琐的事情。所以我们需要借助开发工具,目前不管是Eclipse还是Idea都有类似的生成元数据文件的插件,但这些插件本质上使用的是“bnd工具”,我们先来了解下这个工具。
bnd工具
bnd工具是由OSGI技术主管Peter Kriens开发,bnd工具定义了一些元数据的配置项,这些配置项包含了OSGI模块层中配置项,并且还增加了一些自己独有的配置项(Include-Resource、Private-Package)。注意bnd中定义的配置项的本质作用是用于生成OSGI元数据配置文件中的配置项,也就是说OSGI框架最终识别的还是元数据配置文件。
bnd工具本质上是一个jar包,比如我电脑里的版本是bnd-0.0.384.jar,当然也可以在网上找到其他版本。通过这个工具,可以把一个普通的jar包(不管是自己开发的,还是第三方的)封装成一个被OSGI框架所识别的bundle。
举个简单的例子,现在需要把一个第三方jar包:slf4j-api-1.6.5.jar(用于打印日志)制作成一个公共的bundle(其实官方提供的这个jar已经是一个带有元数据的bundle jar,为了测试可以先把这个文件删掉)。首先需要创建一个*.bnd的文件,这里创建的bnd文件为slf4j-api-1.6.5.bnd,内容为:
Export-Package: * Import-Package: org.slf4j.impl;version=1.6.0
执行如下命令:
java -jar bnd-0.0.384.jar build -classpath slf4j-api-1.6.5.jar -output out slf4j-api-1.6.5.bnd
就会在out目录下重新生成一个slf4j-api-1.6.5.jar,这个jar相比之前多了一个元数据文件MANIFEST.MF,内容如下:
Manifest-Version: 1.0 Export-Package: org.slf4j.helpers;uses:="org.slf4j.spi,org.slf4j",org. slf4j;uses:="org.slf4j.helpers,org.slf4j.impl,org.slf4j.spi",org.slf4 j.spi;uses:="org.slf4j" Bundle-SymbolicName: slf4j-api-1.6.5 Bundle-Name: slf4j-api-1.6.5 Bundle-Version: 0 Bundle-ManifestVersion: 2 Bnd-LastModified: 1517232511103 Import-Package: org.slf4j.impl;version="1.6.0" Created-By: 1.8.0_65 (Oracle Corporation) Tool: Bnd-0.0.384
通过这种方式可以把一个普通jar包(或者几个)封装为一个bundle,但这种命令行的方式还是显得很繁琐(更多关于bnd命令参数可以参考这里http://xjf975999.iteye.com/blog/1322057),也不方便管理,在正式环境中很少使用。在正式环境中,更多的使用maven插件进行打包,比如接下来介绍的maven-bundle-plugin插件(本质上是对bnd工具的封装,不用自己写命令行)。
maven-bundle-plugin插件
maven-bundle-plugin是Apache Felix项目中提供的一个maven插件,在项目的pom.xml文件中引入这个插件,并做一些简单的配置后,执行maven的打包命令 就可以自动生成一个bundle jar。下面展示一个简单的示例,目的是把servlet-api-2.5.jar这个第三方jar封装成一个独立的bundle。完整的pom.xml配置如下:
4.0.0 servlet com.sky.bundles 1.0-SNAPSHOT bundle org.eclipse.osgi org.eclipse.osgi 3.7.1 provided javax.servlet servlet-api 2.5 org.apache.felix maven-bundle-plugin true javax.servlet servlet servlet bundle gantianxing 1.0.0 servlet-api;scope=runtime com.sky.servlet.activator.ServletActivator javax.servlet.* org.osgi.framework
这里重点关注以下几点:
1、
2、Export-Package指令,用于指定该bundle需要导出哪些包,可以使用通配符(*)和否定符(!)。这里配置的javax.servlet.*,最终会导出javax.servlet 、javax.servlet.http、javax.servlet.resources这三个包。默认是*,可以自动导出所有包
3、Import-Package指令,用于指定该bundle需要导入哪些包。默认是*,可以自动导入所有用到的包。
4、Embed-Dependency,用于jar包合并,可以实现把多个第三方jar包合并成一个公共的bundle,这里只配置了一个jar包servlet-api,它会自动识别到dependency中相应的jar包。
5、Bundle-Activator,指定自定义的激活器,这个不是必须的。
其他配置项跟模块层中介绍的配置项都是一样的,不用一一解读。另外如果不配置configuration节点,所有配置项都是采用默认值。更多关于maven-bundle-plugin插件的介绍可以直接查看官网:http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html
可以看到这个pom.xml的配置与普通的配置方式只有些许差别,然后直接运行maven 打包命令,就可以生成bundle jar了。我这里使用的是idea开发工具,运行maven package 在target目录下会有一个新的jar包生成 servlet-1.0-SNAPSHOT.jar,其内容跟servlet-api-2.5.jar基本相同,只是新增了一个激活器和元数据文件MANIFEST.MF:
Manifest-Version: 1.0 Bnd-LastModified: 1517295026912 Build-Jdk: 1.8.0_65 Built-By: gantianxing Bundle-Activator: com.sky.servlet.activator.ServletActivator Bundle-Description: servlet bundle Bundle-ManifestVersion: 2 Bundle-Name: servlet Bundle-SymbolicName: javax.servlet Bundle-Vendor: gantianxing Bundle-Version: 1.0.0 Created-By: Apache Maven Bundle Plugin Embed-Dependency: servlet-api;scope=runtime Export-Package: javax.servlet;version="1.0.0",javax.servlet.http;uses: ="javax.servlet";version="1.0.0",javax.servlet.resources;version="1.0 .0" Import-Package: org.osgi.framework;version="[1.6,2)" Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.5))" Tool: Bnd-3.5.0.201709291849
通过这种方式可以把自己写的代码连同一些列的第三方jar包打成一个大的bundle jar,一次性的加载到OSGI框架中,其他bundle导入对应的包即可使用。
另外在idea开发工具中完成上述配置后,ctrl+shift+alt+s 可以看到这里自动创建了一个OSGI bundle,配置信息如下:
如果看过上一篇博客的朋友,应该注意到了 这些配置本来需要我们手动配置的,如果使用maven-bundle-plugin插件这里已经自动完成了。你也可以像上一篇博客中提到,可以把这个bundle放到idea集成的equinox框架中执行。
总结
前一篇博客中讲到使用idea开发工具的插件可以用于生成元数据配置文件,本次使用maven-bundle-plugin插件生成元数据配置文件。最终我们发现其实两者是想通的,相比而言使用maven-bundle-plugin插件会更方便些,直接跟maven打包命令集成。
但他们本质上都是基于bnd工具实现的(其它的元数据生成工具或者插件,基本都是基于bnd实现的),有时候我们也可能需要直接使用bnd命令来制作一个bundle jar。在日常开发中,如果使用的maven来构建项目,还是建议使用maven-bundle-plugin插件。