This website uses cookies to ensure you get the best experience. Learn More.
译文:OSGi Module依赖
原文作者:David H Nebinger
原文地址:https://web.liferay.com/web/user.26526/blog/-/blogs/osgi-module-dependencies
如有问题,欢迎在原文下面讨论,也欢迎在这里留言。
假设在Liferay DXP平台上开发module的时候,遇见了需要运行环境(runtime)的依赖的时候,该怎么办?
在这片简短的文章中,我会介绍几种方法...
假设你有一个module需要iText(和iText的依赖)作为依赖。这其实和module本身的功能关系不是很大,但是你现在有这个依赖,需要一种方法来使用它。
这种方法最简单也最粗暴。所有在全局类加载器(比如tomcat的lib和lib/ext)中的类可以被所有类访问,包括Liferay OSGi容器。
但是全局的jar有全局的问题。不仅所需要的jar需要在全局目录,所有jar的依赖也需要在全局目录。并且全局类只有一个版本,其他的消费类无法使用不同的版本。
方法 2 - 让OSGi处理
这个是第二简单的方法,但是可能无法使用。如果你在module中声明一个运行环境的依赖,并且OSGi中有一个bundle可以满足依赖的话,module会使用使用这个依赖。
当你确认OSGi中依赖可以被使用的时候,这个方法就可以使用。因为这个方法是利用portal中已有的依赖,或者你之前已经部署到OSGi容器中的依赖(有些jar可能已经包含了OSGi bundle的信息,可以直接部署到容器中)。
例如,假设我们要声明iText依赖,虽然iText应该不会作为bundle已经部署到了OSGi中,所以如果依赖OSGi容器来使用iText很可能会出错的。现在仅是用作举例
使用build.gradle文件来声明运行环境依赖。这段代码是用来声明iText运行环境依赖的
runtime group: 'com.iowagie', name: 'itext', version: '1.4.8'
如果iText(和其依赖)已经成功的部署到OSGi容器中,通过运行环境依赖声明就可以在你自己的module中使用了。如果iText不可用,你的module就不会启动,并且会报错 -- 依赖无法满足。
像那些巨型jar一样,巨型module会拥有所有依赖的类直接暴露在module jar中。
使用Gradle和BND很好实现。
在build.gradle中,你应该像方法2中一样声明运行环境依赖。
并且通过在bnd.bnd中包含所需的资源使module成为一个巨型module:
Include-Resource: @itext-1.4.8.jar
在这里引入依赖jar,一般在gradle下来依赖或者浏览maven库的时候都可以看到具体版本。
要注意的是,也需要引入依赖所以依赖的jar。例如,iText2.08依赖于BouncyCasle mail和prov,所以这些依赖也需要添加:
Include-Resource: @itext-2.0.8.jar,@bcmail-138.jar,@bcprov-138.jar
也需要在build.gradle中添加这些依赖,以便gradle引入这些jar。
如果使用zip工具打开module jar包的话,会看见所有依赖的jar会被解压,class文件会被直接放在module jar包中。
最后的方法是在module中引入jar,和巨型module不一样,这个方法将整个jar包含到module jar中
和方法2,3相似的是,也需要在build.gradle中声明运行环境依赖。
引用jar是在bnd.bnd中完成的。
首先需要定义Bundle-ClassPath属性来引入module jar和其余的依赖jar。在下面的例子中,我指定iText jar会包含在module jar中:
Bundle-ClassPath:\ .,\ lib/itext.jar
这里我们不使用Include-Resource声明,而是使用-includeresource来-将jar引入到bundle中:
-includeresource:\ lib/itext.jar=itext-1.4.8.jar
在这里,我们将itext-1.4.8.jar包含到module中,保存为lib/itext.jar。itext-1.4.8是通过Gradle导入的运行环境依赖。
这种语法也支持通配符,可以有效利用build.gradle选择版本的特性。这个例子是用来包含任何版本的commons-lang:
-includeresource:\ lib/itext.jar=itext-1.4.8.jar,\ lib/commons-lang.jar=commons-lang=[0-9]*.jar
如果使用压缩软件打开module的jar文件的话,可以看到jar文件会在lib文件夹下。
实际项目中应该使用哪种方法?和Liferay开发一样,因需而异。
全局方法适用于只需要一种版本的jar包并且需要用到大量的依赖的情况。例如,项目中有20个不同的module全部依赖于iText 1.4.8,这样,全局方法就是最好的选择。
第二种方法只用于依赖jar是OSGi bundle的情况。在这种情况下,你可以使用不同的版本,并且不用担心去编辑bnd文件。
第三种和第四种方法是最常用的放法。在上面这些情境下,你的依赖是包含在module中的,OSGi类容器中的类是不会被不同版本的ja“污染”的。并且,module也是不依赖于当前容器环境的,因为module自己已经包含了所有的依赖,运行环境也不需要为module事前准备依赖。
我个人很喜欢使用第四种方法,以为巨型jar在解压缩类的时候,可能会有路径上的交错(例如xml和配置文件)。第四种方法就不会有这样的问题。
希望你喜欢
Bundle-ClassPath:\ .,\ lib/gwt-servlet.jar,\ lib/gson.jar -includeresource:\ lib/gwt-servlet.jar=gwt-servlet-2.8.0.jar,\ lib/gson.jar=gson-2.8.0.jar
Import-Package: \ !com.google.gwt.xhr.client.*,\ !com.google.gwt.core.*,\ !com.google.gwt.dev.*,\ !com.google.gwt.i18n.*,\ !com.google.gwt.json.*,\ !com.google.gwt.junit.*,\ !com.google.gwt.thirdparty.*,\ !com.google.gwt.uibinder.*,\ !com.google.gwt.user.*,\ !com.google.gwt.util.*,\ !jsinterop.*,!javax.annotation.*,!javax.imageio.*,!javax.lang.model.*,\ !javax.tools.*,!javax.validation.*,!org.apache.*,!org.objectweb.*,\ !org.w3c.*,!sun.*,!junit.framework,\ *