可移植性、炸鱼薯条

工程 | Rod Johnson | 2008年5月9日 | ...

很高兴在 JavaOne 现场和网上听到关于 SpringSource 应用平台 的如此多的讨论。其中最有见地的评论之一来自 WebSphere 事务架构师 Ian Robinson

这一切是否会影响 WebSphere?核心 Spring 框架没有任何改变。无论 SpringSource 应用平台未来如何,核心 Spring 框架项目仍然与 WebSphere 相辅相成。就像炸鱼薯条一样。
Ian 完全正确。SpringSource 应用平台是 Spring 部署的另一个选择。...没有任何改变。

SpringSource 应用平台清单头

工程 | Glyn Normington | 2008年5月8日 | ...

SpringSource 应用平台由 OSGi bundle 构建而成,并支持同样由 OSGi bundle 构建的应用程序。该平台支持 OSGi 的标准功能,但也支持一些额外的清单头。有些人问过 为什么 SpringSource 添加了专有头? 以及 新头的语义是什么?,因此本文解释了背景动机以及 Import-LibraryImport-Bundle 的语义。

标准 OSGi Bundle 支持

该平台基于 OSGi R4.1 标准构建,如果您愿意,也可以说是 JSR 291,并使用 Equinox 作为其 OSGi 实现。因此,您可以使用平台的工具开发标准 OSGi bundle,并将这些 bundle 部署到平台上,许多用户自平台发布以来一直在这样做。

因此,熟悉 OSGi 的开发者可以将平台用作标准的 OSGi 容器,并受益于平台的功能,例如

  • 能够使用 Admin Console 或通过将 bundle 放入平台的 pickup 目录来部署 bundle,
  • 诊断功能,例如解析失败诊断、应用程序特定跟踪和自动死锁检测,
  • 与 Spring 和 Spring Dynamic Modules 的强大集成,适合希望使用这些框架的开发者,以及
  • 从仓库自动提供依赖项。
然而,该平台还旨在让对 OSGi 几乎或完全没有接触的企业应用开发者也能轻松受益于 OSGi,这对平台提出了一些额外要求。

企业应用程序的额外要求

正如 Sam 最近关于平台部署选项的博客所解释的,您可以在平台上部署现有的单体 WAR 文件,无需理解 OSGi - 平台会为您处理一切。但要受益于共享库、共享服务,以及最终的 PAR 文件作用域,需要将单体 WAR 文件分解为 OSGi bundle。这有多难?

嗯,过程中的一些步骤相对容易,特别是如果遵循了良好的软件工程实践并将代码组织成了服务、领域和基础设施组件。这些组件可以转换为 bundle,并且它们之间的依赖关系可以使用 META-INF/MANIFEST.MF 中的标准 OSGi Import-Package 和 Export-Package 头来表达。

更困难的一步是表达对企业框架(如 Spring 和 Hibernate)的依赖。完全可以使用标准的 OSGi Import-Package 和 Require-Bundle 头来表达这些依赖关系,如果您的目标是创建可以在其他 OSGi 容器中运行的 OSGi bundle,这正是您应该做的,但这种方法有一些隐性成本。

首先,开发者必须精确决定一个给定框架包含哪些包。仅仅导入应用程序代码使用的包是不够的,因为一些企业框架在应用程序加载时会将进一步的依赖项织入到应用程序的字节码中。开发者必须(很可能通过反复试验)发现需要导入哪些额外的实现包,以确保织入的应用程序行为正确。

然后是框架版本迁移的麻烦,因为组成框架的精确包集合可能已经改变。织入所需的额外包通常不是由公共契约定义的,因此可能会发生变化。

此外,由此产生的包导入未能正确捕获设计意图,这使得将来维护或扩展应用程序更加困难。

我们真的不想将这些负担强加给用户,因此我们创建了一些 SpringSource 应用平台特定的额外清单头,即 Import-LibraryImport-Bundle,作为表达对企业框架依赖关系的便捷方式。正如您将在下面看到的,这些头实际上只是用标准 OSGi 包导入来表达的 语法糖

Import-Library

基本语法与其他清单头类似
    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,则在没有合适的库可用时,该库导入将被忽略。

因此,例如,以下头导入 Spring Framework 库 2.5 或更高版本,但在没有合适的库可用时将被忽略

    Import-Library: org.springframework.spring;version="2.5";resolution:=optional

导入多个库

如果您需要导入多个库,则在单个 Import-Library 清单头中指定一个逗号分隔的库导入列表,如下例所示
    Import-Library: org.foo.p;version="[1,2)",org.bar.q;version="[2,3)"

Import-Bundle

Import-Bundle 是另一种便捷方式,适用于库只包含一个 bundle 且创建库定义不方便的情况。其语法与 Import-Library 非常相似,只是它引用的是 bundle 的符号名和版本,而不是库的。

正如您所预期的,对于每个导入的 bundle,平台会选择具有给定符号名和在给定版本范围内平台仓库中可用的最高版本的 bundle。然后,平台将 bundle 导入替换为一组与该 bundle 导出的包匹配的包导入。

因此,例如,以下头导入了 Hibernate 对象关系映射器 bundle

    Import-Bundle: com.springsource.org.hibernate;version="[3.2.6,3.2.7)"

为什么不重载 Require-Bundle

如果您熟悉 OSGi,您可能会问自己为什么我们没有重载 Require-Bundle,而是引入了 Import-Bundle

嗯,我们希望 Require-Bundle 保留其标准语义,包括合并拆分包(split package)各个部分的能力。但我们希望 Import-LibraryImport-Bundle 具有与 Import-Package 相同的底层语义,以避免拆分包带来的复杂性。

我们还预计,随着平台的不断发展,我们需要在 Import-LibraryImport-Bundle 中添加更多指令,而这些指令不适合添加到 Require-Bundle 中。

下一步是什么?

平台 beta 项目 正在进行中,我们将听取所有关于平台功能的反馈,包括新的清单头。

对于希望利用平台头部,但需要生成能在其他 OSGi 容器上运行的 bundle 的用户,我们计划开发一个工具来替换 Import-LibraryImport-Bundle...

SpringSource 应用平台部署选项

工程 | Sam Brannen | 2008年5月6日 | ...

自上周三发布 SpringSource 应用平台以来,许多开发者下载了 1.0.0 beta 版本并开始试用平台。因此,人们开始问:"如何将我的应用部署到平台上,我有哪些部署和打包选项?" 此外,开发者急切地要求查看可用的示例。作为回应,S2AP 团队将在未来几周内发布一些示例应用程序,展示这些功能及更多内容,但在您获得这些示例之前,我想先给您一个高层次的...

Spring Web Services 1.5.1 发布

发布 | Arjen Poutsma | 2008年5月4日 | ...

尊敬的 Spring 社区成员:

我很高兴宣布 Spring Web Services 1.5.1 已发布!

下载 | 网站 | 更新日志 | 公告

这是 Spring-WS 1.5 系列的第一个 bug 修复和增强版本。它修复了自 1.5.0 以来报告的所有 bug,并引入了框架中的各种增强功能

  • 引入了一个使用 OXM marshaller 的 Spring JMS MessageConverter
  • 引入了一个使用 OXM marshaller 的 Spring MVC View
  • 修复了与 SAAJ 消息结合使用 WSS4J 时的 WS-Security 签名问题
  • 支持 HTTP 传输中的超时
  • 支持 Castor 1.2,参见下面的说明
  • Airline 示例现在使用 Spring Security

以及更多。详细信息请参见更新日志。

请注意,由于向后兼容性问题,CastorMarshaller 现在需要 Castor 1.2 或更高版本。

祝好,

Arjen Poutsma
Spring Web Services Lead

使用 SpringSource 应用平台在 OSGi 上运行 Spring 应用

工程 | Rob Harrop | 2008年5月2日 | ...

许多人一直在问,SpringSource 应用平台到底为 Spring 应用做了什么,使其在 OSGi 下运行良好,这超出了 OSGi 和 Spring Dynamic Modules 开箱即用的能力。Adrian 昨天的文章强调了一些一般性问题,现在我们来看一些细节。

在 OSGi 上运行 Spring 应用的三个最具挑战性的方面是

  • 加载时织入
  • Classpath 扫描
  • 线程上下文类加载器管理

其余但不太有趣的问题包括:JSP 支持、TLD 扫描、注解匹配和资源查找。总的来说,需要解决一系列相当大的问题,才能使应用程序顺利部署。

加载时织入

加载时织入是支持起来最麻烦的功能之一。在基本层面,它需要挂接到 Equinox ClassLoader 中,以便在 defineClass 调用期间可以附加和使用标准的 ClassFileTransformers。此外,许多 LTW 用法需要访问一个可丢弃的 ClassLoader,用于检查类型以决定在织入期间需要发生什么,而不会影响真实的 ClassLoader

这种基础级别的支持实际上相当容易实现。困难在于当织入由一个 bundle 中的类驱动,但另一个 bundle 中的类需要被织入时。这在企业应用中非常常见,其中一个 bundle 包含领域实体,另一个 bundle 包含使用 JPA EntityManager 的类型。平台通过确保应用程序中的所有 bundle 都可以使用适当的 ClassFileTransformers 进行织入来处理这种复杂性。

当您开始将织入传播到其他 bundle 时,您确实需要知道何时停止。如果您只是简单地将织入应用于所有 bundle,那么应用程序将相互干扰。平台通过明确限定织入的作用域,使其仅应用于应用程序中的模块来防止这种情况发生。

LTW 的另一个问题是它使刷新复杂化。当一个 bundle 被刷新时,OSGi 将刷新所有依赖于它的 bundle。这意味着,在我上面给出的示例中,刷新领域 bundle 将导致 EntityManager bundle 被刷新。然而,刷新 EntityManager **不会**刷新领域 bundle,这意味着织入可能不同步。平台通过将刷新传播到受织入影响的其他 bundle 来处理此问题。

Classpath 扫描

对于 classpath 扫描,主要问题是 Equinox 不暴露标准的 jar:file: 资源。平台在中间放置了一个适配器,以便库能够看到它们所期望的资源协议。这产生了一个很好的副作用,使得**许多**第三方库能够工作 - 这不仅仅是针对 classpath 扫描的修复。

线程上下文类加载器管理

许多第三方库使用线程上下文 ClassLoader 来访问应用程序类型和资源。OSGi 中的每个 bundle 都有自己的 ClassLoader,因此,在任何时候只有一个 bundle 可以被暴露为线程上下文 ClassLoader。这意味着如果一个第三方库需要查看分布在多个 bundle 中的类型,它将无法按预期工作。

平台通过创建一个 ClassLoader 来解决这个问题,该 ClassLoader 导入应用程序中每个模块导出的所有包。然后,该 ClassLoader 被暴露为线程上下文 ClassLoader,从而使第三方库能够看到应用程序中所有导出的类型。

这只是平台解决的问题的一小部分,但希望它能让您了解平台对 Spring Framework 用户意味着什么。

Spring Security 2.0.1 发布

发布 | Ben Alex | 2008年5月2日 | ...

Spring Security 2.0.1 现已可用。

下载 | 更新日志 | 公告 | 网站

Spring Security 2.0.1 提供了针对最近发布的 2.0.0 版本的一些修复。它还在 OSGi 支持、扩展命名空间配置和加密强度令牌生成方面提供了一些进一步改进。它与 2.0.0 版本完全向后兼容,可以作为 JAR 替换文件直接使用。

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

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

** 5月2日更新,包含案例研究:- 详情请参见本文底部 ** 我相信大多数阅读这篇博客的人昨天都已经看到了 SpringSource 应用平台的发布公告。如果还没有,请务必查看 Rob 的博客文章,其中描述了一些动机、编程模型和路线图。

本文中,我想直接回答几个常见问题。之后,我将描述另外两个令人振奋的公告,它们是对 SpringSource 应用平台本身的补充,但昨天并未成为头条新闻:...

介绍 SpringSource 应用平台

工程 | Rob Harrop | 2008年4月30日 | ...

经过数月的紧张编码,我很高兴宣布 SpringSource 应用平台 1.0 的 beta 版本发布。

2007 年初,我们开始讨论与企业 Java 代名词的单体且重量级的应用服务器的可能替代方案。客户正在寻找一个轻量级、模块化且足够灵活的平台,以满足他们的开发和部署需求。

Spring 和 Tomcat 的组合证明了开发者和运维人员可以在生产环境成功使用轻量级平台。尽管这种组合取得了成功,但缺乏模块化以及对非 Web 应用的明确支持限制了其适用性和灵活性。

我们着手构建 SpringSource 应用平台,以满足这些要求并消除这些限制。

平台的核心是动态模块内核(Dynamic Module Kernel,简称 DMK)。DMK 是一个基于 OSGi 的内核,它充分利用了 OSGi 平台的模块化和版本化特性。DMK 构建在 Equinox 之上,并扩展了其供应(provisioning)和库管理能力,同时为平台提供了核心功能。

SpringSource Application Platform Architecture

为了保持最小的运行时 footprint,DMK 供应子系统会按需安装 OSGi bundle。这使得应用程序可以安装到正在运行的平台中,并且其依赖项可以从外部仓库获取。这不仅消除了手动安装所有应用程序依赖项的需要(这会很繁琐),而且将内存使用量保持在最低。

DMK 本身只需要最少的一组 bundle 即可运行,并通过配置一个 profile 来精确控制加载哪些额外的模块。例如,DMK 不需要 Tomcat 存在,但默认的平台 profile 包含了 Tomcat,以便部署 Web 应用程序。如果您想运行一个不带 Tomcat 的平台,只需编辑 profile 即可,它将不会被安装。(如果您尝试这样做 - 请记住移除 Web 支持意味着 Web 模块将不再部署,因此删除 pickup 目录的内容,这样平台启动时就不会尝试安装 Admin 和启动屏幕应用程序。)安装了 Admin Console 的默认平台配置仅占用 15MB 内存。

我在企业 Java 中一直感到沮丧的一点是,应用程序经常被生硬地塞进人为设计的孤岛中,并且缺乏对不同应用类型的明确支持。考虑一个在线商店的应用。该应用有一个 Web 前端、一个消息驱动的订单处理模块、一个批处理驱动的库存补货模块和一个 B2B Web 服务模块。如今,许多这样的应用程序会被打包成 WAR 或 EAR,模块看起来非常相似,对模块类型之间的差异支持很少。有趣的是,许多人会将此类应用称为 Web 应用程序,而不是带有 Web 模块的应用程序。

在 SpringSource 应用平台中,应用程序是模块化的,每个模块都有一个描述其类型的 personality:web、批处理、web 服务等。平台以 personality 特定的方式部署每种 personality 的模块。例如,web 模块在 Tomcat 中配置 web context。应用程序中的每个模块都可以独立于其他模块进行更新,同时保留作为更大应用程序一部分的身份。无论您构建何种应用程序,编程模型都保持标准 Spring 和 Spring DM。

在 1.0 平台版本中,我们支持 webbundle 类型的模块(personalities),这使您能够构建复杂的 Web 应用程序。未来的版本将包括对更多 personality 的支持,详情稍后介绍。

构建应用程序

平台支持三种打包形式的应用程序

  1. Java EE WAR
  2. 原始 OSGi bundle
  3. 平台档案 (PAR)

平台直接支持标准的 WAR 文件。部署时,WAR 文件会转换为 OSGi bundle 并安装到 Tomcat 中。所有标准的 WAR 契约都得到遵守,您现有的 WAR 文件应该可以直接放入并部署,无需更改。

任何符合 OSGi 标准的 bundle 都可以直接部署到平台中,并且可以充分利用针对 Import-PackageRequire-Bundle 引用的任何依赖项的即时供应(on-the-fly provisioning)功能。

PAR 格式是平台打包和部署应用程序的推荐方法。PAR 只是 OSGi bundle(模块)的集合,它们被分组到一个标准 JAR 文件中,并带有一个唯一标识应用程序的名称和版本。PAR 文件作为一个整体单元部署到平台中。平台将从 PAR 中提取所有模块并安装它们。第三方依赖项将在需要时即时安装。

PAR 格式相比直接将 bundle 部署到平台具有三个主要优点。首先,它更简单。一个中等大小的企业应用可能包含 12 个以上的 bundle - 手动部署这些会过于繁琐。其次,PAR 文件在应用程序中的所有 bundle 周围形成一个明确的作用域,这防止了使用重叠类型或服务的应用程序相互冲突。这个作用域也用于一些高级功能,如加载时织入,以确保一个应用的织入不会干扰另一个应用的织入。最后,PAR 形成一个逻辑分组,定义哪些模块是一个应用的一部分以及该应用有哪些第三方依赖项。管理工具使用这个分组来提供应用程序的详细视图。典型的 PAR 应用程序看起来像这样

PAR File Structure

应用程序中模块之间的依赖通常使用 Import-PackageExport-Package 来表达。对第三方库的依赖也可以用相同的方式表达,但对于许多库来说,这可能容易出错且耗时。使用像 Hibernate 这样的库时,您通常需要导入比最初预期更多的包。为了绕开这个问题,您可以使用 Require-Bundle,但这有一些语义上的问题,例如拆分包(split packages),其中一个逻辑包被拆分到两个或更多类加载器中,导致运行时出现问题。平台引入了两种引用第三方依赖的新机制:Import-BundleImport-LibraryImport-Bundle 类似于 Require-Bundle,但它避免了拆分包和 Require-Bundle 的其他问题。Import-Library 提供了一种机制,可以在单个声明中引用由一组 bundle 导出的所有包,例如 Spring Framework 中的所有 bundle

Bundle-SymbolicName: com.myapp.dao.jdbc
Bundle-Version: 1.0.0
Import-Bundle: org.apache.commons.dbcp;version="1.2.2.osgi"
Import-Library: org.springframework.spring;version="2.5.4.A"

这里我有一个模块 bundle,它依赖于 Commons DBCP bundle 和 Spring Framework 库。Spring Framework 库包含在您的应用程序中使用 Spring 所需的所有 bundle。

Import-LibraryImport-Bundle 在底层会扩展为 Import-Package,因此与标准 OSGi 语义一致。

平台理解模块的 personality,并由此可以推断如何配置模块的执行环境。部署 Web 模块时,典型 Spring MVC 应用程序所需的全部 servlet 基础设施会自动创建,从而消除了在不同应用程序中重复创建这些样板代码的需要。在 1.0 最终版本中,将向 Web 模块 personality 添加更多智能功能,以支持额外的技术,例如 Spring Web Flow。

无论您选择哪种打包格式,编程模型都只是 Spring Framework 和 Spring Dynamic Modules,其他 Spring Portfolio 产品在其之上运行。

可服务性

可服务性是整个工程团队的一个关键考虑因素。我们花了大量时间担心日志消息的格式和堆栈跟踪的大小,以确保诊断应用程序问题尽可能容易。每当我们发现重复且耗时的任务时,我们都会寻找自动化或完全消除它的方法。

为了辅助问题诊断,平台对日志消息和跟踪消息进行了严格区分。日志消息供最终用户查看,让您可以轻松获取最重要的故障信息,而无需遍历海量跟踪内容。所有应用程序故障都在日志输出中显示并编码 - 这些代码是访问知识库或支持内容的便捷方式。要理解为什么这如此有用,请看平台启动时的以下输出

[2008-04-29 12:12:01.124] main                     <SPKB0001I> Platform starting.
[2008-04-29 12:12:04.037] main                     <SPKE0000I> Boot subsystems installed.
[2008-04-29 12:12:06.013] main                     <SPKE0001I> Base subsystems installed.
[2008-04-29 12:12:07.396] platform-dm-1            <SPPM0000I> Installing profile 'web'.
[2008-04-29 12:12:07.674] platform-dm…

Web 应用程序与 OSGi

工程 | Costin Leau | 2008年4月29日 | ...

自 Spring Dynamic Modules 的第一个里程碑以来,在 OSGi 中运行 Web 应用程序的需求开始出现。这可能是最常被请求的功能之一,不足为奇的是,一旦 1.0 最终版本发布,Web 支持就成为了 1.1 分支的主要焦点。我很高兴地报告,随着刚刚发布的 M2 版本,正如 Juergen 已经暗示的,Spring-DM 不仅支持普通的 WAR(自 1.1.0 M1 起可用),还支持在 OSGi 内部运行的 Spring-MVC 应用程序。在本篇文章中,我想简要讨论典型的 OSGi Web 场景和 Spring-DM 的方法。但首先,

为什么要在 OSGi 中部署 WAR?

简单的问题:OSGi 原生地提供了版本控制、包连接和热重载。想象一下在您的应用程序中利用这些功能:您可以停止将库嵌入到WEB-INF/lib并开始在您的 Web 应用之间共享它们,避免标签库重复(同时保持多个版本运行),并在运行时只更新应用程序的某些部分。这尤其有用,因为 Web 应用往往是分层的,因此在其生命周期中会发生大量变化。

为什么 OSGi 中的 Web 应用会遇到问题?

Servlet 规范围绕着 web 容器 的概念展开:一个为 Web 组件提供运行时环境的服务,提供标准服务,如生命周期管理(对象创建和销毁、线程分配)、并发、HTTP 请求处理等等。另一方面,OSGi 平台也作为一个受管环境运行,具有服务注册表、包连接和版本控制(仅举几例)。为了解决这个问题,OSGi 委员会设计了 Http Service,这是 compendium 规范的一部分。

...

订阅 Spring 新闻通讯

随时了解 Spring 新闻通讯

订阅

提升自我

VMware 提供培训和认证,助您快速提升。

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一次简单订阅。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部