完善画面:Spring、OSGi 和 SpringSource 应用平台

工程 | Adrian Colyer | 2008 年 5 月 1 日 | ...

** 5 月 2 日更新,新增案例研究 - 请参见本文末尾的详细信息 **我相信,阅读本文的大多数人昨天都看到了 SpringSource 应用平台的发布公告。如果没有,请务必查看Rob 的博文,其中描述了一些动机、编程模型和路线图。

现在我想在本文中直接解决一些常见问题。之后,我将介绍另外两个令人兴奋的公告,它们补充了 SpringSource 应用平台本身,但昨天并没有成为头条新闻:SpringSource 企业捆绑包存储库和 Eclipse 的应用平台工具。这些共同完成了围绕基于 OSGi 的企业应用开发与 Spring 的故事。

我在过去 24 小时内多次听到的一个问题是:OSGi 有什么问题 - 为什么我们不能只使用普通的 OSGi 服务平台(例如 Equinox、Felix 或 Knopflerfish)而不是 SpringSource 应用平台?

OSGi 绝对没有问题。

OSGi 是一个很棒的基础和服务平台 - 这就是我们和许多其他人选择在其基础上构建的原因。它在广泛的行业和应用中得到验证,并且是 Eclipse 和 IBM 的 WebSphere 以及其他几个供应商的中间件堆栈的基础。

直接针对 OSGi 规范 API 进行编程缺乏我们对企业应用期望的一些特性 - 例如使用依赖注入和创建易于在容器外部进行单元和集成测试的应用。直接针对 OSGi 规范 API 进行编程还会迫使您在相对较低的级别处理 OSGi 平台的动态性 - 当您依赖的模块和服务在运行时停止、启动、安装和更新时,您该怎么办?但是,这里没有我们无法使用Spring Dynamic Modules项目克服的根本障碍。使用 Spring Dynamic Modules 构建的应用可以在任何标准 OSGi 服务平台上运行,我们对所有构建都针对 Equinox、Felix 和 Knopflerfish 进行测试。我们致力于确保 Spring Dynamic Modules 和基于 Spring 的编程模型保持运行时中立。随着 SpringSource 应用平台的推出,这一立场不会改变。

现有的企业库也没有任何问题。

好吧,确实有一些情况不太理想,但总的来说,我们知道如何使它们满足企业应用开发的需求。

那么问题出在哪里呢?

如果 OSGi 运行良好,并且现有的企业库满足了我们的需求,那么问题出在哪里呢?困难在于,当您尝试将 OSGi 服务平台与一组并非为 OSGi 设计的现有企业库结合起来时。这不是 OSGi 的错,它有一个很棒的模型,可以提供出色的模块化、版本控制和操作控制。也不是企业库的错 - 它们并非为在 OSGi 下运行而编写。但是,使 OSGi 如此有吸引力的特性破坏了这些企业库开发人员做出的假设。例如,OSGi 的模块化模型阻止您看到其他人捆绑包的私有部分。这正是您想要的,直到您意识到您的企业库无法再看到您的应用类型。很多东西都可能出错:从 commons logging 到 jsps、标签库到数据源、加载时织入到组件扫描、资源加载到 orm 映射。列表还在继续......(是的,当您将应用代码及其所需的所有库打包到一个捆绑包中时,您可以使其中许多东西正常工作,但这完全忽略了重点!)

这就是为什么您会看到很多人在 OSGi 之上构建,但很少有将 OSGi 的优势传递到应用编程模型中的案例(Eclipse RCP 是一个罕见的例外)。当您在 OSGi 之上构建,但不一定公开该模型以供最终用户应用开发时,您可以根据 OSGi 模型构建并使事情正常工作。当您需要提供一个平台,在这个平台上可以使用大量现有的企业库时,情况就不同了。如果我们可以抛弃所有这些,并从专门为 OSGi 编写的库开始,那我们就没问题了。例如,我们已经确保 Spring Framework 能够完全在 OSGi 服务平台内部运行。但这并不是一个现实的选择。或者,我们可以等待现有库的开发人员将它们全部转换为开箱即用地在 OSGi 下运行(就像我们对 Spring 所做的那样)。但除非其他人也这样做,否则他们为什么要这样做呢?所以我们似乎陷入了先有鸡还是先有蛋的困境。这是 OSGi 企业专家组在过去一年中花费大量时间讨论的问题。SpringSource 应用平台解决了这个问题:它通过使具有标准 OSGi 语义的标准 OSGi 捆绑包与现有的企业应用库一起工作,从而将企业应用开发引导到 OSGi 的世界中。

我还想再次强调,该平台不仅仅与 OSGi 相关:OSGi 支持是我们最兴奋的功能之一,但 SpringSource 应用平台也是一个用于部署标准 war 文件的出色服务器平台。我们将在以后的文章中描述该平台在这种情况下提供的优势。

希望本文有助于澄清围绕 SpringSource 应用平台与 OSGi 的确切关系的一些困惑。如果您一直在关注,您可能已经发现了另一个潜藏的问题:使现有的企业库在 OSGi 下工作很好,但是您是否需要将所有 jar 文件转换为 OSGi 捆绑包才能部署它们?是的,你需要。事实证明,如果您想正确地对所有导入和导出进行版本控制并确保您拥有正确的符号名称等,那么这将是一项艰巨的工作。好消息是,对于数百个常用的企业应用库,我们已经为您完成了艰苦的工作,并在 SpringSource 企业捆绑包存储库中提供了可用的 OSGi 就绪版本......

SpringSource 企业捆绑包存储库

SpringSource 企业捆绑包存储库既可以作为 Ivy 和 Maven 使用的存储库,也可以作为企业库的在线可搜索数据库。您可以在www.springsource.com/repository找到它。您可以按名称浏览捆绑包,或者只需输入搜索词即可查找名称、导出的包、类或资源匹配的捆绑包。您还可以查看任何捆绑包的最小(仅满足所需依赖项)和最大(尽可能满足可选依赖项)传递依赖项。

来自常见问题解答

"SpringSource 企业捆绑包存储库是常用开源库的集合,用于使用 Spring Framework 开发企业 Java 应用。存储库包含 jar 文件(捆绑包)和库定义(“.libd”)文件。库定义了一组通常一起用于某种目的的捆绑包(例如,“Spring Framework”库)。存储库中包含数百个捆绑包。" 存储库满足以下标准

  • 存储库中的每个 jar 文件都是一个有效的 OSGi 捆绑包。您可以将从存储库下载的任何 jar 文件按原样部署到 OSGi 服务平台和 SpringSource 应用平台中。它也可以用作 OSGi 外部的常规 jar 文件。
  • 每个捆绑包和库都与其关联的完整版本信息。捆绑包的包导出信息包含版本信息,捆绑包的包导入信息包含完整的版本范围兼容性信息。
  • 存储库是传递完整的。任何捆绑包的强制依赖项都保证也在存储库中。任何存储库中捆绑包的大多数可选依赖项也将存在。库定义中列出的捆绑包保证在存储库中。
  • 存储库是一致的。在将任何工件上传到存储库之前,我们都会验证它是否可以与存储库中的所有其他捆绑包一起安装、解析和启动在 OSGi 服务平台(使用与 SpringSource 应用平台相同的配置文件)中。
  • 存储库可以从基于 Ivy 和 Maven 的构建中使用。
为了维护这些保证,我们已在存储库中工件的发布周围实施了一个治理模型。有一个 JIRA 实例,您可以针对它提出包含其他库的请求,并报告现有已发布工件的任何问题(与 OSGi 清单等相关)。

应用开发工具

到目前为止,我们已经讨论了用于将应用开发为 OSGi 捆绑包的基于 Spring 的编程模型、可部署到 OSGi 服务平台的企业库的可用性以及使这些遗留库能够在 OSGi 运行时中工作的运行时(SpringSource 应用平台)。拼图中缺少的部分是使创建基于 OSGi 的应用变得简单的开发工具。

Eclipse 已经内置了 OSGi 开发工具。由于每个 Eclipse 插件也是一个 OSGi 捆绑包,因此 Eclipse PDE 工具(插件开发环境工具)可用于 OSGi 应用开发。但是,这些工具主要用于 Eclipse 插件的开发这一事实很明显,并且在将它们用于 OSGi 应用开发时存在一些常见的挫折感。一个问题是 META-INF/MANIFEST.MF 文件只能放置在项目的根目录中 - 这与 Ivy 和 Maven 等构建工具不兼容,另一个问题是您只能为整个工作区使用一个目标平台(要针对其进行开发的捆绑包集合)。PDE 工具的优点在于,它确实需要构建项目的编译类路径,并根据 OSGi 清单进行构建,因此您的类路径和类可见性在编译、测试和运行时之间没有差异。

除了 SpringSource 应用平台之外,我们还发布了一组 Eclipse 插件(可在 SpringSource 应用平台下载页面获取),这些插件使 OSGi 应用的开发变得更容易,特别是针对 SpringSource 应用平台的应用。您的 META-INF/MANIFEST.MF 文件可以位于任何源目录中,并且工具会根据清单条目构建编译类路径。但是,您可以将您的项目与定义到 Eclipse 的 SpringSource 应用平台服务器(使用 WTP 功能)相关联,而不是使用单个目标平台。然后,您的项目的类路径将从清单中的导入语句派生,并针对工作区中的其他捆绑包项目和已安装到关联服务器中的捆绑包进行解析。在编译时,您将获得与运行时完全相同的类路径和依赖项解释。当然,正常的“部署到服务器”选项也可以使用。

以下是服务器在 Eclipse 中运行时的样子:

此屏幕截图显示了如何使用“Bundle Dependencies”类路径容器管理类路径。请注意,在清单文件中未导入的包会显示为灰色,表示您当前无法访问它们。

更好的是,我们能够利用 OSGi 的模块化特性。一组项目(每个捆绑包一个)构成了您的应用程序。当您更改项目中的任何内容时,一个额外的增量构建器会分析资源增量并对 SpringSource Application Platform 中正在运行的捆绑包进行实时更新——因此您始终运行最新的代码:每次都运行,一直运行。这极大地提高了生产力和开发体验。

案例研究

Matt Raible 发布了一篇博文,讲述了他尝试在使用 Freemarker 的 OSGi 下运行 Spring Web 应用程序(不使用 SpringSource Application Platform)的经历。这似乎是一个很好的测试应用程序,可以验证我上面关于使现有企业库能够工作的论述。好消息是,此应用程序可以在 SpringSource Application Platform 上愉快地运行。以下是我使其运行的步骤(总时间约 10 分钟)
  • 从 Matt 的博客下载 zip 文件
  • 运行 'mvn'
  • 将 target/mpapp.war 复制到平台的 pickup 目录
  • 启动平台:bin/startup.sh。
我在控制台中得到了以下输出
com.springsource.platform.deployer.core.DeploymentException: Unable to satisfy constraints of 'myapp' version '0.0.0':
Cannot resolve: myapp  Unsatisfied leaf constraints:
Bundle: myapp_0.0.0 - Import-Package: org.springframework.osgi.web.context.support; version="0.0.0"
Did you mean: 'org.springframework.osgi.context.support'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.ext.servlet; version="0.0.0"
Did you mean: 'javax.servlet'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.core; version="0.0.0"
Did you mean: 'org.hamcrest.core'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.template; version="0.0.0"
Did you mean: 'org.antlr.tool'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.cache; version="0.0.0"
Did you mean: 'org.apache'?
这些是预期的消息,因为我没有在平台中安装 freemarker 或 osgi.web.context 支持捆绑包。
  • 访问 http://www.springsource.com/repository。在搜索框中键入“freemarker”,找到匹配的条目并点击链接下载它。将下载的捆绑包复制到 repository/bundles/usr 中
  • 简化清单以指向平台上的新捆绑包和库。原始清单如下所示
Import-Package: javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
org.springframework.osgi.web.context.support, org.springframework.context.support,
org.springframework.web.context, org.springframework.web.context.support,
org.springframework.web.servlet, org.springframework.web.servlet.mvc,
org.springframework.web.servlet.mvc.support, org.springframework.web.servlet.view,
org.springframework.ui, org.springframework.web.servlet.view.
freemarker, freemarker.cache,freemarker.core,freemarker.template,freemarker.ext.servlet
我将其简化为
Import-Package: org.apache.commons.logging
Import-Library: org.springframework.spring;version="[2.5.4,3.0.0)"
Import-Bundle: com.springsource.freemarker;version="2.3.12"
当我们知道您正在部署 Web 应用程序时,常用的导入会在部署时自动添加。Import-Library 和 Import-Bundle 允许您方便地在单个语句中引用库和捆绑包。我还删除了“Bundle-Classpath”条目,因为应用程序平台会自动检测 WEB-INF/lib 中的库并将其添加到捆绑包类路径中。
  • 我编辑了 web.xml 并注释掉了 context-param 声明,因为这里不需要使用自定义应用程序上下文类型
  • 再次运行 'mvn',并将 myapp.war 复制到 pickup 目录。
  • 应用程序平台自动重新部署了应用程序
  • 在浏览器中访问 https://127.0.0.1:8080/myapp/ .... 成功!
我认为这是一个很好的演示,展示了平台在简化企业库在 OSGi 下运行路径方面的价值主张。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

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

了解更多

即将举行的活动

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

查看全部