我们构建 OSGi 应用的计划

工程 | Rob Harrop | 2009 年 3 月 18 日 | ...

近日来,我们注意到人们对由 OSGi bundle 组成的应用的构建解决方案的未来越来越感兴趣。由于我们深度参与 OSGi,这件事情与我们息息相关,我们花费了大量时间研究客户需求以及这些需求的解决方案。在这篇博客文章中,我将概述我们已确定的需求,并提出我们认为能满足这些需求的解决方案。

我非常期待听到任何有额外需求、认为我们的需求是虚假的或有更好解决方案想法的人的意见。

OSGi 构建的需求

依赖元数据不重复

当前 OSGi 构建的一个真正问题是依赖元数据可能在许多地方重复。对于 dm Server,我们在 ivy.xml、.classpath 和 MANIFEST.MF 文件中都描述了依赖关系。OSGi 构建的任何长期解决方案都必须要求依赖元数据只有一个存放位置。

与现有构建解决方案协作

考虑到 OSGi 应用的独特特性,尝试从头开始构建系统是很诱人的。我们曾经考虑过这个想法,但很明显,这在技术上是不可行的,也不是为我们的用户提供的最佳解决方案。

我们的用户对其选择的构建解决方案投入巨大,让他们迁移似乎不符合实际。相反,用户希望有一个能很好地融入他们现有 Maven 或 Ant 构建的解决方案。

自动生成 manifest 文件

迁移到 OSGi 的最简单方法可能是开始从应用模块的相关元数据自动生成 manifest 文件。理想情况下,这种方法将最大程度地减少对应用代码或开发人员处理代码方式的更改。

从 OSGi manifest 派生构建依赖

尽管生成 manifest 文件是一种有效的方法,但许多用户对将他们的 OSGi manifest 文件视为依赖元数据的规范描述很感兴趣。这些用户希望从他们在 manifest 文件中编写的元数据来驱动构建。为了支持轻松创建 manifest 文件,许多用户希望看到对 manifest 模板的支持。manifest 模板允许自动生成样板 manifest 内容,同时让用户能够完全控制版本等重要信息。

这种方法将 manifest 文件用作 IDE 和离线构建中的中心依赖描述符。开发人员手动编写 OSGi manifest 文件,或借助工具编写,然后构建工具会使用该 manifest 文件,其方式类似于 Maven 使用 pom.xml 和 Ivy 使用 ivy.xml。

使用 OSGi 元数据进行解析可以在构建期间应用完整的 OSGi 解析规则。这将使得构建时依赖解析与运行时发生的解析更加准确地匹配。

这种方法的一个潜在缺点是开发人员需要在他们的 manifest 文件中指定测试依赖项。Maven 和 Ivy 都有标记仅用于测试环境的依赖项的方法,当使用 manifest 文件进行依赖解析时,也需要类似的解决方案。

场景

根据这些需求,我们推导出了四种主要场景。有趣的是,每种场景都代表了我与 dm Server 经常交互的一个或多个用户。

1. Maven 和 Eclipse - pom.xml 驱动

与下一个场景一样,这是我们最常遇到的场景,也是我们目前投入最多时间研究的场景。采用这种方法时,开发人员进行开发任务的方式与他们处理任何普通 Maven/Eclipse 项目时一样。

OSGi manifest 文件由 Maven 和 Eclipse 的插件生成。开发人员可以选择让 Eclipse 插件作为增量构建的一部分或按需重新生成 manifest 文件。

生成 OSGi manifest 所需的大部分元数据可以在 Java 代码(源文件/字节码)中找到。然而,从字节码中无法推断出合理的依赖版本号。在这种情况下,可以从 pom.xml 文件或可自定义的 manifest 模板中提取版本。

manifest 模板可以承载除版本号以外的更多信息,允许开发人员添加 OSGi 属性和指令以及任何自定义头部信息。

2. Ant、Ivy 和 Eclipse - ivy.xml 驱动

这种方法类似于 Maven 的 pom 驱动方法,不同之处在于依赖元数据将从 ivy.xml 文件中提取,而不是从 pom.xml 文件中提取。

开发人员可以使用 Ant 任务在构建的适当阶段执行 manifest 文件生成。

这种方法最大的缺点是 Eclipse 中缺乏强大的 Ivy 集成。对于 Ivy 2,Eclipse 插件的支持非常不足。我们正在考虑的一种方法是从生成的 manifest 文件创建 Eclipse classpath。这是我们已经支持的工具,并将为接下来的两个场景进行扩展。开发人员将编写 ivy.xml 文件,使用 Eclipse 插件生成他们的 manifest 文件,并让 Eclipse classpath 自动更新。

3. Maven 和 Eclipse - MANIFEST.MF 驱动

在这种方法中,OSGi manifest 文件是项目依赖元数据的最终声明。开发人员可以选择完全手动编写 manifest 文件,但更有可能的是他们会编写一个 manifest 模板,然后让我们的插件完成其余工作。

dm Server 工具已经包含了一个由 manifest 文件驱动的 Eclipse classpath 容器,这将扩展以支持准确的传递性依赖解析。

为了支持此环境中的测试,插件将允许同时编写 MANIFEST.MF 和 TEST.MF 文件,其中 TEST.MF 描述仅用于测试的依赖项,而 MANIFEST.MF 描述在测试和生产过程中都适用的依赖项。

对于此场景,最后剩下的一块是如何接入 Maven。我们目前正在研究两种方法:替换/集成 Maven 依赖解析器或生成 pom.xml 文件。我很想听听您对哪种方法最有价值且对您最有益的看法。

4. Ant、Ivy 和 Eclipse - MANIFEST.MF 驱动

这种方法与以 manifest 文件驱动的方式使用 Maven 非常相似。与场景 2 不同,此场景不受 Ivy/Eclipse 集成不足的影响,因为我们将使用与场景 3 中相同的 manifest 文件驱动的 Eclipse classpath 容器。

OSGi 构建工具

为了满足上述要求,我们正在构建一套与 Maven、Ant 和 Ivy 协同工作的工具套件,为构建 OSGi 应用提供集成解决方案。

Bundlor

Bundlor 是我们内部使用了一段时间的工具,用于生成 OSGi manifest 文件。我们主要用它来创建您在我们 企业 Bundle 仓库 中看到的所有 bundle。Bundlor 可用于为创建时未过多考虑 OSGi 的遗留库生成 manifest 文件。Bundlor 也可用于为您专门针对 OSGi 创建的 bundle 生成 manifest 文件。Bundlor 消除了创建高质量 bundle manifest 所涉及的大部分繁琐工作。

Bundlor 支持 manifest 模板的概念,允许您自定义生成的 manifest 文件。使用模板,您可以为包的导入和导出添加版本和属性,从导出中排除包,在无法自动检测时添加导入,还可以添加额外的 manifest 头部信息。下面的代码片段展示了我们一个示例应用的 manifest 文件。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: GreenPages Service
Bundle-SymbolicName: greenpages
Bundle-Vendor: SpringSource Inc.
Bundle-Version: 1.0
Import-Template: org.springframework.*;version="[2.5.6.A,3.0)"
Excluded-Exports: greenpages.internal

在此示例中,使用了 Excluded-Exports 头部信息来防止 greenpages.internal 被暴露。使用 Import-Template 头部信息为所有匹配 org.springframework.* 模式的包名设置版本。项目代码被扫描以确定可能的导入和导出集合。然后使用模板文件控制该集合中的哪些导入/导出实际进入 manifest 文件以及它们的版本是什么。重要的是,生成过程会为您正确生成 uses 元数据,这消除了最繁琐的工作之一。

Bundlor 实际上会支持创建两个 manifest 文件:MANIFEST.MF 和 TEST.MF。TEST.MF 文件将用于描述仅在测试期间需要的依赖项。这对于希望使用 manifest 驱动构建但不希望用测试依赖项污染生产 manifest 文件的开发人员来说非常重要。

在接下来的几周,我们将发布 Bundlor 的第一个公开里程碑版本。在此版本中,您将能够在 Ant 和 Maven 中为项目生成 manifest 文件,并能够使用 manifest 模板自定义这些文件。在之后的几个里程碑版本中,我们将增加从 pom.xml 和 ivy.xml 文件自动检测依赖项版本的功能。

为了赶上 Bundlor 1.0 最终版,我们将把我们大部分示例中的手动编写 manifest 文件切换为使用 Bundlor 和 manifest 模板。此外,我们也将把 dm Server 迁移到 Bundlor,放弃所有手动编写的 manifest 文件。

BundlorEclipse

BundlorEclipse 是一个 Eclipse 插件,它让 Bundlor 的功能直接在您的 Eclipse IDE 中可用。使用此插件,您可以将完全增量的 manifest 文件生成作为您正常 Eclipse 构建生命周期的一部分来执行。如果像我一样,您在保存按钮上过于随意,您可以将 BundlorEclipse 配置为仅在需要时才生成 manifest 文件。

将其与即将发布的 dm Server 容器内测试框架结合使用时,您将能够启动完整的 dm Server 测试环境,包括所有 bundle 的 manifest 文件,这一切都可以在 Eclipse 中完成。

离线依赖解析器

OSGi 有其自己的规则来解析模块之间的依赖关系以及如何验证这些依赖关系并将其转化为一致的类空间。在 OSGi 之外,构建工具工作在平面的 classpath 上,该 classpath 列出了要搜索类的 JAR 包和目录。

为了支持 manifest 驱动的构建,我们将创建一个离线依赖解析器,它无需启动 Equinox 或 dm Server 即可执行 OSGi 解析。我们将把它与一个工具配对,该工具将把 OSGi 解析图展平为用于编译和测试的简单 classpath。这个展平过程将完全由用户配置,用户将能够提供策略信息来管理 OSGi 图中的多个版本如何映射到 classpath 中的单个版本。

Manifest classpath 容器

使用依赖解析器,我们将能够改进我们的 manifest classpath 容器,为每个 Eclipse 项目创建一个完整的、传递性的 classpath。

Maven/Ivy 依赖解析器/pom.xml/ivy.xml 生成器

依赖解析器也将构成我们依赖解析器/pom.xml/ivy.xml 生成器工具的核心部分。这里的关键观察是,作为开发人员,您应该期望在 Eclipse 内部和构建工具中获得一致的结果。

为什么是 Bundlor 而不是 Bnd?

您可能知道,OSGi 技术总监 Peter Kriens 提供了一个名为 bnd 的工具,其用途与 Bundlor 类似。我们最初的立场是在我们自己的项目中使用 bnd,并将其作为我们工具的一部分。实际上,早在 Bundlor 出现之前,Spring Dynamic Modules 就已经使用 bnd 创建其 bundle 了。那么,为什么我们决定创建 Bundlor 呢?

创建 Bundlor 的主要原因是我们必须支持 bnd 中不存在的一些附加功能,例如:

  • 基于 JDT 的源代码扫描
  • 部分代码处理
  • 增量 manifest 创建

这些功能用于支持 BundlorEclipse。我们在 Eclipse 中使用基于 JDT 的扫描代替字节码扫描,以改善用户体验,并更好地集成到 Eclipse 构建生命周期中。Eclipse 对部分正确的代码处理得很好,我们希望 Bundlor 也能以类似的方式支持部分代码。

在 BundlorEclipse 中,可以将 Bundlor 配置为在您每次在 IDE 中保存更改时运行。为了提高性能,我们支持增量 manifest 文件生成。当您更改代码时,Bundlor 可以跟踪需要对 manifest 文件进行的更改,并避免重新创建所有 manifest 文件。

与 Eclipse 以外的 IDE 协作

我们知道,尽管 Eclipse 是 Java 开发人员的主流 IDE,但仍有相当一部分开发人员使用 IntelliJ 和 NetBeans 等 IDE。

虽然我们不承诺亲自为这些 IDE 构建任何插件,但我们将把所有描述的工具开源,以便其他人可以为他们喜欢的 IDE 创建插件。

我们构建工具的方法是尽量将尽可能多的功能封装到通用库中。我们致力于与 NetBeans 和 IntelliJ 团队合作,帮助他们将我们的工具库集成到他们的 IDE 中。

理想的最终结果是,无论您使用什么 IDE,您仍然可以访问相同的底层 OSGi 工具。

其他需求

OSGi 构建的需求并不仅限于我概述的这 4 种场景。还有更多功能和增强功能可以改善开发人员使用 OSGi 应用的体验。

批量生成 bundle

许多公司会有大量非 OSGi bundle 的 JAR 文件积压。我们计划扩展 Bundlor 以支持批量生成 bundle。在此模式下,您可以将 Bundlor 指向一个 JAR 文件目录,让 Bundlor 为所有这些文件创建 bundle,从而节省时间。此外,Bundlor 还能够利用这些文件之间的关系来确定依赖项的版本范围应该是什么。这将减少您必须编写的模板代码量,同时仍然生成高质量的 bundle。

仓库驱动的代码补全

使用 manifest 驱动的构建方式构建 dm Server 应用时,您必须手动编写初始的 manifest 导入。通过支持仓库驱动的代码补全,您将能够在 Eclipse 中针对 dm Server 仓库获得代码补全,这将同时生成 Java 导入和 manifest 导入。使用此功能,您可以根据需要构建 manifest 依赖项,而无需切换到 manifest 文件。

订阅 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

保持领先

VMware 提供培训和认证,助力您的职业发展。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中为 OpenJDK™、Spring 和 Apache Tomcat® 提供支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部