管理OSGi依赖地狱

21

更新2:由于我的博客有点不活跃,链接已经过期,您可以在此处查看文章:

https://www.dropbox.com/s/xvobgzqnl43kcda/Managing_OSGi_Transitive_Dependencies__Part_1____CitizenRandom.pdf?dl=0

https://www.dropbox.com/s/0bdooux4yhrf8lf/Managing%20OSGi%20Transitive%20Dependencies%20%28...pdf?dl=0

https://www.dropbox.com/s/km3mxqah6oy23iq/Why%20using%20Require-Bundle%20is%20a%20bad%20pract...pdf?dl=0

https://www.dropbox.com/s/mtenchtjopcrmr8/How%20many%20ways%20can%20we%20import%20bundles%20in%20OSGi_%20_%20CitizenRandom.pdf?dl=0

https://www.dropbox.com/s/sldxynx3fl8vn61/Managing%20OSGi%20Transitive%20Dependencies%20%282...pdf?dl=0

我有一个Maven项目,使用了非常著名的Felix Maven Bundle插件,并在我的POM.XML中以以下方式进行了配置:

<packaging>bundle</packaging>

(...)

<plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName>
                    <Bundle-Version>${project.version}</Bundle-Version>
                    <Export-Package>jlifx.*</Export-Package>
                    <!-- <Embed-Dependency>*</Embed-Dependency> -->
                </instructions>
            </configuration>
        </plugin>

然后我的POM文件中还包含一些一级依赖项:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.1</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>5.0.0.Alpha1</version>
    </dependency>
</dependencies>

现在我的问题开始了...如果我执行mvn install,我将获得非常好的MANIFEST.MF和其他东西构建完成的组件包,但我将无法获取其他依赖的组件包。这意味着,如果我将我的组件包文件拖放到我的OSGi框架实例上,我会得到类似于"Unable to resolve 1.0: missing requirement [1.0] osgi.wiring.package; (&(osgi.wiring.package= etc..."这样的东西。

所以,我发现一种创建我的第一层依赖项组件包的方法是通过在我的POM中创建一个配置文件,如下所示:

<profiles>
    <!-- http://www.lucamasini.net/Home/osgi-with-felix/creating-osgi-bundles-of-your-maven-dependencies -->
    <!-- -Pcreate-osgi-bundles-from-dependencies bundle:wrap -->
    <profile>
        <id>create-osgi-bundles-from-dependencies</id>
        <build>
            <directory>${basedir}/bundles</directory>
            <plugins>
                <plugin>
                    <groupId>org.apache.felix</groupId>
                    <artifactId>maven-bundle-plugin</artifactId>
                    <version>2.0.1</version>
                    <extensions>true</extensions>
                    <executions>
                        <execution>
                            <id>wrap-my-dependency</id>
                            <goals>
                                <goal>wrap</goal>
                            </goals>
                            <configuration>
                                <wrapImportPackage>;</wrapImportPackage>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

执行 mvn -Pcreate-osgi-bundles-from-dependencies bundle:wrap 命令后,我将得到经过完善构建并且可用的 bunldes,但这里有一个真正的问题。这些 bundles 会依赖于它们自己的一些其他 bundles,因此需要将这些 bundles 的依赖项也作为 bundles 进行打包。根据许多网页的说法,我们以前有一个 mvn org.apache.felix:maven-bundle-plugin:bundleall 目标来为我们完成此操作,但我尝试过,它存在缺陷并返回异常,而且已被标记为弃用,根据 Stuart 的说法,它将在 maven 2.4.1 及以后版本中删除 (参考:https://issues.apache.org/jira/browse/FELIX-4145)。

所以现在我的唯一解决方案就是手动检查每个我的一级依赖关系的清单,并通过 Google 查找包含所需软件包的 jar,将它们添加到我的 POM.XML 中作为 maven 依赖项,然后运行 mvn -Pcreate-osgi-bundles-from-dependencies bundle:wrap 将它们封装为 bundles。

这就是所谓的依赖地狱...

有没有办法自动化解决一个 maven-bundle osgi 项目的所有 nth 级依赖关系?例如,让 maven 研究每个一级依赖项的清单文件,读取导入包,并在中央仓库中查找提供此类包的 jar 文件,下载并将它们打包为 bundles?

注意:请提供详细的说明以实现此操作,不要只是链接到可能解决此问题的此工具或那个工具。这些工具的主要问题是缺乏示例和文档。例如,bundleall 已被弃用,但似乎没有工具可以替代它,至少在 maven bundle plugin 的官方文档中如此...

谢谢!





编辑-1:

感谢您迄今为止给出的答案 :)

我认为我没有以最合适的方式解释我的情况,我感到有些难以通过纯文本来做到这一点。或者我可能没有理解你的回答。我在 OSGi 方面相当“新手”,我唯一的知识来自书籍(如 OSGi in Action)和 Google。

想象一下,我的 bundles 导入 A 和 B 包。然而,A 包导入 C 包,B 包也导入 C 包。但是现在 C 导入 D、E、F 和 G 包。另一方面,D 包导入了大量其他包,E、F 和 G 也如此。

我的计算机中只有我自己的bundle和提供A和B包的bundles,因为它们是我的一级依赖项。然而,我没有任何其他所需的bundles,即使它们作为jar文件安装在我的JDK安装文件夹中,我也没有它们作为bundles,甚至不知道从哪里获取jar文件来包装它们(实际上我知道,但让我们假设我不知道)。
我希望构建工具运行类似以下算法的操作:
1) 转到我的bundle MANIFEST.MF并读取Import-Package字段。枚举所有所需的包及其各自的版本。
2) 在互联网的某个地方搜索我的所需库的jar或bundle。
3) 下载每个并检查它们是否只是普通的jar文件或者具有有效的OSGi清单文件(即它们是bundle)。
3.1) 如果它们是bundle,则将它们复制到我的bundles/文件夹中。
3.2) 否则,使用任何工具将jar打包成bundle,并将bundle复制到我的bundle/文件夹中。
4) 现在,对于每个新下载/创建的bundle,重复步骤1),2),3)和4)。
我想要的最终结果:对于我直接或间接依赖的每个库,都有一个bundle,以便我可以在我的OSGi Framework实例(如felix或equinox)中即时安装它们。
我不想要的:
1) 手动进行此操作,因为如果我尝试解决每个依赖项的依赖项,我可能需要花费几个小时或几天来收集和打包jar文件。
2) 将所有依赖项嵌入到一个ubber/mega bundle中。根据我阅读的几本书,这是一种糟糕的做法,它更难以单独维护每个依赖项,并且会破坏模块化。
注意:我的问题不在于将jar打包成bundle的特定任务,而在于递归地处理每个bundle的导入,即使它们需要从诸如Maven中央之类的在线存储库中下载。
是否有自动执行此操作的方法,或者我对OSGi漏掉了非常大的东西?这么大的东西,我永远不需要做我所要求的事情吗?
编辑-2:
某些(如果不是全部)Import-Package依赖项可以在运行时解决。想象一下,OSGi Framework尝试启动一个bundle,但是不是显示“无法解析8.0:缺少要求[8.0]osgi.wiring.package;”,它将搜索该包在线,下载并即时安装。生活会变得容易得多。

1
如果我理解你的意思正确,你想要构建包含大量依赖JAR的捆绑包?你是否误解了OSGi?如果你想将整个应用程序打包成一个存档文件,你可以创建一个EBA,并使用useTransitiveDependencies=true来包含所有第三方库。 - Martin Baumgartner
嗨,不,我不想将它们全部打包成一个归档文件(归档= .jar文件对吧?)。我只想让Maven为我的项目生成每个传递依赖项的捆绑包存档。理想情况下,他会读取我的捆绑包的import-package字段,列出包名称和版本,转到Maven的中央存储库,从那里获取所需的库,将不是捆绑包的库包装成捆绑包,并将它们粘贴到我的项目文件夹中。然后对每个传递依赖项执行相同的操作。 - PedroD
我认为你误解了bundle的含义。Bundle是一个容器,包含了所有特定类、其他包的导入语句(包括版本或版本范围)和导出语句。你可以将所有第三方库(如commons-lang、commons-io等)应用到你的应用程序中,并导入必要的语句。即使第三方库有静态字段需要在你的bundle中覆盖,也没关系,因为在OSGi中,每个bundle都有自己的类加载器。 - Martin Baumgartner
wrap/bundleall目标已被Embed-Dependency取代,因此已被弃用。请参考https://dev59.com/Q2kw5IYBdhLWcg3wJXMh。 - Martin Baumgartner
如果您使用Karaf或WebSphere,那么您应该真正关注http://aries.apache.org/modules/applications.html和http://aries.apache.org/modules/ebamavenpluginproject.html。如果您有多个未“osgi-enabled”的库(这是嵌入依赖项的唯一原因,我认为),请检查springsource企业捆绑包存储库http://ebr.springsource.com/和apache-servicemix捆绑包http://search.maven.org/#search|ga|1|g%3A%22org.apache.servicemix.bundles%22。 - Martin Baumgartner
显示剩余6条评论
4个回答

6
如果您想将不是捆绑包但只需要将这些jar作为OSGi框架中的库进行捆绑,您可以使用BND工具对其进行包装。请参见链接如何从现有的第三方jar创建/生成OSGi捆绑包? 但是我可以看到您使用的是已转换为osgi捆绑包的非常常见的库。您可以在SpringSource企业捆绑包存储库中找到许多转换为捆绑包的库。
但是,如果您找不到任何未转换为良好OSGi捆绑包的库,则可以使用PAX-URL中的WRAP协议在OSGi框架中安装这些依赖项。要使用这些协议取决于您正在使用的OSGi框架,但在apache karaf中默认安装。例如,要从maven存储库安装库:
root@karaf> osgi:install -s 'wrap:mvn:commons-lang/commons-lang/2.4$Bundle-SymbolicName=commons-lang&Bundle-Version=2.4'

这条指令从maven仓库安装commons-lang库到OSGi框架,并将其封装为OSGi bundle,同时保留出现在行中的标头。关于自动安装依赖项,您提到第二个编辑,在自动为OSGi框架提供bundle方面有几种解决方案,但需要一些工作量。其中两个主要解决方案是" Felix OBR repository "和"Felix Provisioning" bundles以及Equinox p2存储库。它们都有控制台命令来自动安装bundles和features。问题在于,我现在找不到一个好的公共bundles仓库。您需要建立自己的包含所有必需bundles的仓库。如果您使用maven-bundle-plugin,在将artifacts安装到本地maven仓库时,插件会更新位于您的仓库根目录中的"repository.xml"文件,以反映您的bundles的要求和功能。这个文件是一个OBR仓库文件。

嗨,感谢您的帮助! 是的,我知道几个可以帮助我将jar文件打包成捆绑包的工具。但我的问题比这更大。我已经编辑了我的开头帖子(请参见其底部文本),试图用其他话语来解释我的问题。 再次感谢! - PedroD

4
使用maven-bundle-plugin中的Conditional-Package功能,可以递归地内联所有需要的包到您的JAR捆绑包中,并将标签设置为true以启用该功能。

4
请问@PedroD能否发布你的解决方案,我很感兴趣 :) - reyman64

3
我希望最终的结果是:每个库都有一个捆绑包,我可以在我的OSGi框架实例(如Felix或Equinox)中即时安装它们,因为它们是我直接或间接依赖的库。如果我理解你的问题正确,你想要类似于maven-dependency-plugin这样的东西?
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/thridparty-libs</outputDirectory>
                        <overWriteIfNewer>true</overWriteIfNewer>
                        <includeScope>runtime</includeScope>
                        <excludeGroupIds>${project.groupId}</excludeGroupIds>
                        <excludeArtifactIds>...</excludeArtifactIds>
                    </configuration>
                </execution>
            </executions>
        </plugin>

如果你面临这样的问题,即没有osgi-Manifest但有许多依赖关系,你应该检查它们是否在springsource企业bundle仓库http://ebr.springsource.com/repository/和apache-servicemix bundles http://search.maven.org/#search|ga|1|g%3A%22org.apache.servicemix.bundles%22中可用(如我的评论所述)。

这已经接近了,但仍无法自动化大部分的工作。 我认为有一种配置 OBR 存储库来完成此工作的方法,如果我有任何进展,我会在此发帖与有兴趣的人分享我的解决方案。 谢谢! - PedroD

0

尝试使用p2-maven-plugin,它完全符合您从1到4所描述的内容。实际上,它使用tycho构建p2存储库,但您也可以使用它来收集和捆绑您的依赖项和传递依赖项。

我在这里不写示例,因为在上面的链接中,每个东西都有易于理解的示例进行了充分的文档说明。

希望这可以帮助到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接