抢占先机
VMware 提供培训和认证,助你加速前进。
了解更多SpringSource 应用平台由 OSGi Bundle 构建而成,并支持同样由 OSGi Bundle 构建的应用。该平台支持 OSGi 的标准特性,但也支持一些额外的清单头部。有几个人问过 为什么 SpringSource 添加了专有头部?
和 新头部的语义是什么?
,所以这篇博文解释了 Import-Library 和 Import-Bundle 的背景动机和语义。
因此,精通 OSGi 的开发者可以将该平台用作标准的 OSGi 容器,并受益于平台特性,例如:
嗯,这个过程中的一些步骤相对容易,特别是如果遵循了良好的软件工程实践并且代码已经组织成服务、领域和基础设施组件。这些组件可以转换为 Bundle,并且它们之间的依赖关系可以使用 META-INF/MANIFEST.MF 中的标准 OSGi Import-Package 和 Export-Package 头部来表达。
更困难的一步是表达对企业框架(如 Spring 和 Hibernate)的依赖。使用标准的 OSGi Import-Package 和 Require-Bundle 头部来表达这些依赖关系是完全可行的,如果你的目标是创建可以在其他 OSGi 容器中运行的 OSGi Bundle,这正是你应该做的,但这种方法有一些隐含成本。
首先,开发者必须精确地决定一个给定框架包含哪些包。仅仅导入应用代码使用的包是不够的,因为一些企业框架在应用加载时会将更多的依赖编织到应用的字节码中。开发者必须通过反复试验来发现需要导入哪些额外的实现包,以确保编织后的应用行为正确。
其次,从一个框架版本迁移到下一个版本是一项繁琐的任务,因为构成该框架的精确包集合可能已经改变。编织所需的附加包通常未由公共契约定义,因此可能会发生变化。
此外,由此产生的包导入并不能恰当地体现设计意图,这使得未来维护或扩展应用更加困难。
我们真的不想把这些负担强加给用户,所以我们创建了一些额外的 SpringSource 应用平台特定的清单头部,Import-Library 和 Import-Bundle,作为表达对企业框架依赖的便捷方式。正如你将在下面看到的,这些头部实际上只是 语法糖
,它们最终会被转换为标准的 OSGi 包导入。
Import-Library: <librarySymbolicName>;version=<versionRange>其中 <librarySymbolicName> 是库的
符号名,而 <versionRange> 是使用 OSGi 版本范围表示法表示的库的可接受版本范围。库定义指定了库的符号名和版本,这两者共同唯一标识了平台上的库。
如果你不熟悉 OSGi 版本范围表示法,目前最常用的形式是最低版本范围,例如 2
,表示 版本 2 或更高
,以及 半开
范围,例如 [2.2.1,2.2.2)
,表示大于等于 2.2.1 且小于 2.2.2 的任何版本。如果省略了 version=<versionRange>(当然也包括分号分隔符),则默认范围包含所有版本。
对于每个库导入,平台会选择具有给定符号名并在平台仓库中可用且在给定版本范围内的最高版本库。然后,平台会将该库导入替换为一组包导入,这些包导入与该库 Bundle 导出的所有包匹配。平台会检测一个 Bundle 导入两个或多个导出相同包的库的情况,并发出适当的日志消息,然后阻止安装该导入 Bundle。
例如,以下头部导入了版本在 2.5.4(含)到 2.5.5(不含)之间的某个版本的 Spring Framework 库:
Import-Library: org.springframework.spring;version="[2.5.4,2.5.5)"
:=,它表示一个
指令,用于修改清单头部的语义,与分隔符
=不同,后者表示一个
匹配属性,例如 version。
Import-Library: <librarySymbolicName>;version=<versionRange>;resolution:=optional
如果未指定 resolution,或者指定为 mandatory,则如果不存在具有给定符号名且版本在给定范围内的库,包含该导入库头部的 Bundle 将无法安装。但如果指定了 resolution:=optional,则如果找不到合适的库,该库导入将被忽略。
例如,以下头部导入了版本从 2.5 开始的某个版本的 Spring Framework 库,但如果没有合适的库可用,则会被忽略:
Import-Library: org.springframework.spring;version="2.5";resolution:=optional
Import-Library: org.foo.p;version="[1,2)",org.bar.q;version="[2,3)"
正如你所预期的,对于每个导入的 Bundle,平台会选择具有给定符号名并在平台仓库中可用且在给定版本范围内的最高版本 Bundle。然后,平台会将该 Bundle 导入替换为一组与该 Bundle 导出的包匹配的包导入。
例如,以下头部导入了 Hibernate 对象关系映射 Bundle:
Import-Bundle: com.springsource.org.hibernate;version="[3.2.6,3.2.7)"
嗯,我们希望 Require-Bundle 保留其标准语义,包括合并拆分包的能力。但我们希望 Import-Library 和 Import-Bundle 具有与 Import-Package 相同的底层语义,从而避免拆分包的复杂性。
我们还预计,随着平台的不断发展,我们将需要为 Import-Library 和 Import-Bundle 添加更多指令,这些指令不适合添加到 Require-Bundle。
对于希望利用平台头部,但又需要生成能在其他 OSGi 容器上运行的 Bundle 的用户,我们计划提供一个工具,将 Import-Library 和 Import-Bundle 语法糖替换为等效的标准包导入。
我们还将与 OSGi Alliance 的同事讨论新的清单头部,以确定是否存在适合 OSGi 未来解决的通用需求。