InfoQ 有一个关于 SpringSource Application Platform 发布反响的讨论帖。Michael Burke 在该帖中提出了一个很好的问题,可以概括为“撇开围绕 OSGi 的炒作不谈,如果我将一个当前打包为 EAR 的应用程序移植到 OSGi bundle 中,我能期待看到哪些好处?”。
我开始在 InfoQ 帖中回答这个问题,但我的回答太长,不适合作为评论,所以在这里详细阐述。
这个问题很好。基于 OSGi 的应用程序与传统的基于 JEE EAR 的应用程序之间的主要区别在于模块化程度更高。所以问题变成了,这种改进的模块化能否带来任何好处,如果能,具体是什么?"设计规则,模块化的力量" 这本书对这个问题进行了非常详尽的论述。这本书提供了很好的背景知识,但我感觉 Michael 可能在寻找一些比书中更不理论化的东西!让我们将模块化的好处分为两类:开发时应该期待的好处,以及运行时应该期待的好处。
开发时好处。
- 开发时(以及运行时)严格执行模块边界
OSGi 具有确保开发团队遵守模块边界的机制。使用 OSGi,模块导出的类型需要明确声明(如果未导出,则不可见),模块的依赖关系也需要明确声明(这可以包含版本范围兼容性信息)。这意味着在使用开发工具时,团队无法通过代码自动完成意外地违反模块边界,并且在运行时,OSGi 服务平台会阻止一个模块看到另一个模块的私有内部实现。因此,你的应用程序架构在开发周期中保持整洁和受到保护,而不是通过(通常是无意的)不必要的耦合而缓慢崩溃。- 一种切实可行的服务导向架构,用于管理模块间的服务依赖。
模块间的依赖当然不只局限于类型——模块还需要提供服务(可以理解为 Spring bean)供其他模块使用,并且可能依赖于其他模块提供的服务(再次理解为 Spring bean)。你的应用程序与其本质上是一个大型应用程序上下文,不如将其视为通过本地服务注册表交互的一组对等上下文。Spring bean(组件)对模块来说是私有的,除非明确导出。模块间的 bean 引用由运行时管理。这再次意味着,在模块上工作的开发人员可以自由地进行任何他们喜欢的内部更改,只要外部契约(发布的 bean、导出的类型)保持不变。使用 Spring Dynamic Modules 时,模块的导入和导出类型以及导入和导出服务都是声明式指定的(前者在 OSGi manifest 中,后者在 Spring 配置文件中)。- 更好地按照你想要的方式组织开发团队
“组织结构追随架构”。将一个团队分配给特定的一个或多个模块进行工作很容易。但要求一个团队实现一个跨越许多模块的功能则困难得多。因此,自然而然地,你的技术架构(如何将系统划分为模块)决定了你的组织结构——即你如何在团队和个人之间有效地划分工作。应用程序模块化上的更大灵活性意味着团队结构上的更大灵活性。有时你会看到相反的情况:“架构追随组织结构”。这种情况往往发生在由一些地理位置相近的个体组成分布式团队时。为了做出合理的任务分配,如果可能的话,你会希望将模块与地点对齐。因此,如果你不能移动人员,那么在合理程度上你的架构就受到你的组织的支配。在模块分解方面拥有更大的灵活性,你就越有可能找到适合你的方案。- 更快的团队开发
当模块具有清晰的边界——定义良好的外部接口、详细指定的依赖关系和受保护的内部实现时,负责这些模块的团队可以更容易地并行开发,而不会意外地相互干扰。详细指定的交互更容易进行桩测试 (stub) 和模拟测试 (mock),也更容易集成。这应该会带来更高效的团队和更快的开发周期。- 更快的测试周期
当你在容器内进行测试时,SpringSource Application Platform 的 Eclipse 开发工具利用了 OSGi 服务平台在运行系统中动态更新给定模块的能力。与你的项目关联的增量构建器会在你做出任何更改时自动更新正在运行的平台实例中的模块。这可以是任何更改——代码或其他。例如,如果你在 Web 层工作,持续与你的 Web 应用程序交互并边测试边进行,那么每次更改时 Web 模块都会被刷新——你无需等待你的持久化层每次都被重新初始化。Spring Dynamic Modules 提供的对 bundle(模块)间服务引用的智能管理确保所有模块间链接在刷新后得到修复。这种开发体验非常令人着迷:我已经警告过你!- 作为依赖管理一部分的版本控制支持
当一个模块指定其依赖项时,它可以指定一个版本范围(可以限定为单个版本),表明它兼容的依赖项版本。OSGi 允许在运行时同时存在一个 Java 包的多个版本。这使得团队 A 需要某个库的版本 x,而团队 B 需要同一个库的版本 y(且 x 和 y 不兼容)的场景成为可能。只要模块 A 和 B 之间不需要交换该库中的类型,这就可以无障碍地工作。如果模块 A 和 B确实需要在它们之间交换类型,那么 OSGi 服务平台会在部署时而不是运行时检测到这个潜在冲突(假设两个模块的 manifest 文件已正确生成)。- 减少障碍
与我的其他观点(这些观点普遍适用于 OSGi)不同,这一点是 SpringSource Application Platform 所特有的。我们相信,如果你开始在 SpringSource Application Platform 上开发基于 Spring 和 OSGi 的企业应用程序,与直接针对 OSGi 服务平台进行开发相比(尽管编程和部署模型相同),你在使用企业库时遇到的障碍会少得多,因为后者可能无法按照你在 OSGi 环境下期望的方式工作。
运行时好处
运行时好处源于这样一个事实:OSGi 中的模块不仅仅是开发时的构造。它们在运行时真实存在,拥有自己的生命周期,并且可以在运行系统中进行检查。
- 可以在运行时获得关于已安装模块及其连接的完整信息——这是运维团队以前从未有过的洞察级别。
你可以列出所有已安装的 bundle 及其版本,查看它们导出和导入的包,还可以查看它们导出和导入的服务(以及提供这些服务和包的 bundle 的身份)。以前,运维团队对运行中的应用程序的可见性仅限于 JEE 部署单元级别,OSGi 改变了这一切。(顺便说一句,SpringSource Application Management Suite 提供了更多的洞察,但这属于另一个话题)。- 隔离变更
由于可以独立地安装、卸载、更新和刷新模块,通过将变更范围限定在较小的单元(bundle),可以降低修改生产应用程序的风险。应用程序的其余部分(其他 bundle)可以保持不变。是的,你可能有一个漫长的变更控制流程,这意味着实际执行变更并没有更快,但至少你现在可以在更大程度上确定没有引入任何其他意外差异。- 共享依赖项
OSGi 对版本控制的支持使得在平台中一次安装企业库的可信版本并在应用程序之间共享成为可能。- 只使用你需要的服务器设施
由于服务器平台本身以模块化方式构建在 OSGi 之上,你可以配置平台只包含支持当前在其上运行的应用程序所需的那些服务。
非 OSGi 相关的好处
如果你对 OSGi 毫不在乎呢???SpringSource Application Platform 是否仍能带来好处?
是的,确实如此。
我喜欢这样看待 SpringSource Application Platform
首先,它是一个服务器。一个轻量级、可配置且注重可维护性的服务器(参见Rob 关于该平台的原创文章)。它具有许多有用的功能,例如每个应用程序独立的跟踪和日志文件、死锁检测、故障检测和转储处理、智能线程池和工作窃取等。基于这些原因,它是部署 Web 应用程序的绝佳选择。
其次,它是一个理解基于 Spring 应用程序的服务器。Spring 集成是开箱即用的,部署器可以简化打包和部署基于 Spring 的应用程序的过程——例如,无需为了配置 Spring 的 DispatcherServlet 而使用样板式的 web.xml 文件。
第三,也仅仅是第三,它为终端用户应用程序提供 OSGi 支持,带来了我上面已经概述的好处。