首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

为 WebSphere Application Server 开发企业 OSGi 应用程序(1)

为 WebSphere Application Server 开发企业 OSGi 应用程序(1)

介绍与软件开发相关的绝大部分成本并不是新应用程序的初始设计、开发和测试成本 — 尽管这些成本可能会比较高 — 而是 。
从一致、版本化、可重用的模块(只能通过定义良好的接口访问)设计和构建应用程序和应用程序套件降低了复杂性,并为软件首次发布之后的维护和完善提供了极大的灵活性。模块式设计(其中模块提供定义良好的服务和接口)允许在多个团队之间分配大型项目,各个团队可以专注于各自的任务,不必在公共外部包范围之外理解其他团队的代码细节,从而降低了每个团队的工作的复杂程度,减少了完成任务的时间。另外,通过将应用程序的更改影响范围降到最小 — 假设影响范围能够确定,应用程序的维护成本也得以降低。如果一个模块更改只影响它的内部包,对它的外部包没有任何影响,那么可以只对一个单独的隔离模块进行维护,测试目标也更容易确定。这是显而易见的,但我们可以从开发工具和运行时基础设施的积极帮助中获益,以支持这样一种模块式设计方式。例如,如果有一种更简单的方法来部署和维护多个 EAR 使用的公共代码,难道这不是很好吗?
首先,什么模块才算得上好模块?
  • 该模块应该提供一致的逻辑功能,并且应该足够的独立,表示一个实际的 “重用单元”。
  • 该模块应该通过定义良好的外部接口和依赖项与其他模块松散耦合
  • 该模块应该将它的内部包与其他模块隔离,以便模块的内部行为更改不会影响其他任何模块。
Java 类粒度太小,不能形成应用程序之间的逻辑重用单元,它们的隔离关注主要局限于实例数据的封装。类通常包装在一个代表一致功能的 JAR 文件中。作为一个部署单元(和文件系统中存在的工件),JAR 是一个非常实用的重用单元,但它缺乏作为一个好模块的其他一些特征。
考虑可见性:如果您在包 bar.foo 的类中有一个对其可用的方法,那么您需要使用一个公共访问限定符来声明该方法。您没有办法来表明这个方法是否也应该或不应该对该 JAR 之外的类可用。您可以应用惯例和最佳实践。可以使用一个包命名惯例将您的接口组织到外部和内部包中。例如,专用于 WebSphere Application Server 的接口包含在 com.ibm.websphere 或 com.ibm.wsspi 的子包中,而专用于应用程序的内部接口主要位于 com.ibm.ws 的子包中。如果在不同的模块上工作的不同团队遵守模块外部包的定义和用法,那么这些模块将只通过定义的外部包保持耦合。当然,您的模块中总是有一些 ++ 函数(plus-plus function)不可或缺,但它们不是模块接口的一部分。因此,当另一团队发现这也会使他们的工作更轻松,那么允许他们继续使用这些函数又有什么危害呢?毕竟,你们都在相同的总体项目上工作,且他们将使用的方法都拥有公共 Java 访问能力,因此不必更改代码就可以允许他们使用这些函数 — 如果他们一定要问的话。现在,您无意中打破了 bundle 之间的松散耦合。您的 bundle 的内部包的更改 “影响范围” 现在可能会超出您的 bundle 范围,这使得确定什么受到影响,进而确定需要测试什么更加困难。
那么,现在有一点很清楚:尽管 JAR 是一个非常实用的重用单元,但它缺乏区分内部包和外部包的能力,因此没有办法隔离外部包。比这更糟的是:尽管在另一个环境中提供这个 JAR(您的重用单元)相当容易,但您如何确定这个新环境是否能够满足其拥有的所有依赖项的要求呢?如果您在这上面犯错误,可能就相当于您的手上拿着一个定时炸弹,即它可能一连数天正常运行,然后需要加载这个新环境没有的一个类,这时炸弹爆炸 — ClassNotFoundException。这里的问题是,除了不能提供隔离外,JARs 还不能声明它们自己的依赖项。
看来,JAR 与良好的可重用模块的要求比较接近,但缺乏一些基本的模块特征。这就是 OSGi bundle 发挥作用的时候了。
OSGi bundle 一个 JAR,但它在 JAR 清单文件中拥有附加头部。在没有处理这个附加元数据机制的纯 JVM 中,这个 bundle 的表现与普通 JAR 一致。但在包含一个 OSGi 框架的 JVM 中,这个元数据 被该框架处理,额外的模块特征得到应用。清单 1 展示了一个示例 MANIFEST.MF。
清单 1. 一个 bundle 清单文件中的 OSGi 头部
1
2
3
4
5
6
7
8
9
10
11
12
13
Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: MyService bundle   

Bundle-SymbolicName: com.sample.myservice

Bundle-Version: 1.0.0

Import-Package: com.something.i.need;version="[1.0,2.0)"

Export-Package: com.myservice.api;version=1.0.0




这里需要注意的一些头部是:
  • Export-Package 列出将从这个 bundle 导出的一个或多个包(处于特定版本)。只有导出包在 bundle 外部可见;这里没有列出的包都只在 bundle 内部可见。
  • Import-Package 列出 bundle 需要的一个或多个包(处于特定版本或版本范围)。
我们现在先不涉及版本控制的细节(将在稍后讨论),先来看看这两个头部的作用。还记得吗,前面介绍过,我们需要建立一些开发最佳实践来定义模块的外部接口并确保没有任何内部包被任何客户模块使用。借助 OSGi,现在可以通过在运行时实施来支持这个最佳实践,并可以向模块所有者提供一个机制来适当封装它的内部包。另外,您的包清单文件中包含一些元数据,明确指定 bundle 需要的、需要由其他 bundle 提供的所有包。在一个包含许多 bundle 的复杂应用程序中,这将向您提供一个更确定的方法,以确定一个 bundle 更改的影响,并理解对系统其余部分的可能影响,从而减小软件开发周期中的风险和成本。
元数据处理和可见性规则的运行时实施由 OSGi 框架解算器负责。当每个 bundle 启动时,这个解算器针对此框架中已经安装的其他 bundle 声明的导出协调该 bundle 的每个导入,并为每个 bundle 计算一个单独的类路径。如果某个 bundle 有一个无法解算的依赖项,该 bundle 将不会启动。前面提到过的滴答作响的定时炸弹(针对一个 JAR 被移动到一个不能满足其所有依赖项要求的新环境的情况)被通过移除保险丝而拆除。相比处理一个无法启动的应用程序而言,处理一个正常工作一段时间、然后突然失败并抛出一个 ClassNotFoundException 的应用程序要困难得多。
此前我们所讨论的内容都不是特定于一个企业运行时的 — 那么这些内容如何与企业 Java 应用程序或企业应用程序服务器相关呢?
假设我们有一个企业应用程序服务器能够处理 OSGi bundle 元数据,那么 OSGi 的第一个明显的优势就是包含大量模块的复杂企业应用程序的适当模块化。但 OSGi 的优势远不止这些,它还能解决企业环境中普遍的几个其他问题。我们已经简单接触了这些问题中的一个:在部署了数十或数百个 EAR 的许多大型企业部署中,往往存在这样一种情况:每个 EAR 都是自足的,其程度达到应用程序使用的许多公共库被打包到需要它们的每个 EAR 中。这些库副本将塞满部署这些 EAR 的文件系统和知识库,并在应用程序启动时填满内存。尽管企业应用程序通常可以被部署到各种供应商的企业环境,且管理依赖项已针对独立于这些 EAR 安装的共享库配置,但这些机制因供应商不同而不同,限制了可移植性。另外,共享库配置通常与部署过程本身分离,需要独立的、部署后管理配置,这增加了端到端部署过程的复杂性。
OSGi 元数据和 bundle 知识库向您提供了一个机会,允许您只在应用程序存档中包含特定于应用程序的模块,从而极大地简化共享公共库的企业应用程序套件的部署。在理解 OSGi 元数据之后,企业部署过程变得更加强大,能够针对部署环境中配置的 bundle 知识库的内容解算 bundle 依赖项。所有公共库都可以在一个中央 bundle 知识库中管理,该知识库然后成为企业(单元)配置的一部分。
OSGi 还向您提供了一个机会,允许您在企业环境中更好地执行版本控制工作。当今企业应用程序通常包含对公共库有相似依赖性的第三方框架和库。如果不同框架需要不同版本的公共库,那么这将是个令人头痛的问题。当您遇到下面的情况时,这个问题将变得尤其严重:以前,您的应用程序一切正常,但现在您需要更新一个供应商框架,结果却发现办不到,原因是该框架在应用程序中的另一个框架使用的一个库的不兼容的新版本上有一个依赖项。
OSGi 版本控制元数据和类加载能够消除这个问题。在上面的清单 1 中,Import-Package 头部表明包 com.something.i.need 上的一个依赖项,版本范围 为 “[1.0,2.0)”。这表明这个依赖项的需求范围为 1.0 ≤            version < 2.0 的任何包版本。因此,version 1.0 或 1.5.0 或 1.9 都能满足这个依赖项的需求,但 version 2.0 不能。OSGi 的版本控制机制支持包提供者在版本的主要部分中使用一个标明,一个不兼容更新的更改来表明一个包的新版本是否向前兼容前面的版本。包使用者可以指出他们能够使用的版本或版本范围。(请参阅  了解关于 OSGi 版本控制的更多信息。)重要的是,如果一个应用程序中的两个 bundle 依赖同一个包的不同版本,那么这些依赖项的需求可以同时得到满足,因为 OSGi 解算器可以为这两个 bundle 计算不同的类路径。
OSGi 平台规范,以及参考实现和依从性测试,由  生成,10 多年来一直被广泛使用。2010 年 3 月, 出版物包含了企业环境。该出版物定义了企业 Java 技术的一些 OSGi 语义,比如事务、持久性和 Web 组件。这个重要的规范定义了一些标准机制来将结合 Java EE 和 OSGi 世界,包含了 bundle 元数据来声明该 bundle 包含一个 web.xmm 文件的 Web bundle、包含一个 persistence.xml 文件的持久性 bundle、还是包含一个 blueprint.xml 文件的 Blueprint bundle。Web 和持久性 bundle 只是包含额外 OSGi 清单文件头部的常见 Java EE bundle;而 Blueprint bundle 更像 Spring 模块,但包含一个标准化的 bean 定义 XML。
作为一种技术,OSGi 在独立应用程序和客户端应用程序技术中已经流行了多年,并在许多企业应用程序服务器(比如 WebSphere Application Server)的实现中内部使用。由于缺乏企业应用程序的 OSGi 标准,以及缺乏广泛可用的专用工具和企业运行时支持,在这些应用程序服务器平台上运行的企业应用程序对 OSGi 的直接利用最近受到抑制。随着 OSGi Enterprise Specification 的发布,以及可以选择在越来越多的企业应用程序服务器上将应用程序部署为 OSGi bundle,这种情况得到了改观。
本文余下部分将讨论开发和部署 WebSphere Application Server V7 Feature Pack for OSGi Applications and JPA 2.0 中引入的企业 OSGi 应用程序的运行时和工具化支持:
返回列表