Spring Integration 1.0.3 示例:只需添加 OSGi

工程 | Oleg Zhurakousky | 2009 年 7 月 28 日 | ...

引言

上周,Mark Fisher 向您介绍了随 Spring Integration 1.0.3 新版本发布的、经过重新组织和简化的 Spring Integration 示例,到目前为止,收到的反馈非常积极。除了重组和简化现有示例之外,我们还引入了一些新的示例,目的是展示在基于 OSGi 的平台上运行 Spring Integration 的一些好处。在这篇博客中,我们将使用一个非常简单但功能强大的例子,来探讨 Spring Integration 和 OSGi 结合使用时,如何应对当今企业的动态性。

Spring Integration 是一个基于 POJO 的轻量级、可嵌入的消息传递框架,它采用一种松耦合的编程模型,旨在简化基于 企业集成模式 的异构系统集成,而无需单独的 ESB 引擎或专有的开发和部署环境。另一方面,OSGi 是一种范式,它允许从称为 OSGi Bundles 的独立模块构建松耦合的系统。从一组独立开发的模块构建系统可能不是什么新范式,我们(希望如此)已经这样做了很多年。话虽如此,OSGi 模块化的真正好处并非来自于其静态打包模型,而是来自于对其部署和运行时动态性的理解,以及它如何很好地适应当今业务流程的动态性。

那么,让我们通过一个简单的例子看看基于消息交换的集成和OSGi 的动态性如何互补,从而实现一个非常强大且动态的系统。

Spring Integration 示例与 Spring Integration 的发行版一起提供。您也可以从这里单独下载。为了简化,这些示例被开发为 SpringSource Tool Suite (STS) 项目,同时利用 dm Server 工具快速集成 SpringSource dm Server - 一个基于 OSGi 和 Spring 的企业 Java 平台。然而,作为符合 OSGi 规范的项目,这些示例可以在任何配置正确的 OSGi 平台上充分运行。

环境

首先,确保我们拥有一个配置正确的开发/部署环境。

要配置 STS/dm Server 环境,请按照以下步骤操作

此处 下载并解压 STS 从 此处 下载并解压 SpringSource dm Server

Spring Source Tool Suite v2.1.x 将自带预配置的 SpringSource dm Server,但了解如何手动配置它仍然有所帮助。
打开 STS 并配置 dm Server:打开Server View -> 在 Server 视图的空白处右键单击 -> New -> Server

picture-14

选择 SpringSource -> SpringSource dm Server v1.0 -> Next

指向您安装服务器的根目录

picture-22

点击Finish

picture-3

您现在已经在 STS 环境中配置了 SpringSource dm Server。启动 dm Server 并确保它成功启动且没有错误。

假设您已经下载了 Spring Integration 示例,现在让我们使用 STS/Eclipse 提供的“Import Existing Projects into the workspace”向导将这两个示例项目导入工作区。File -> Import -> General -> Existing Projects into Workspace -> Next 浏览到 samples 目录的位置并选择 osgi-inboundosgi-outbound 项目

picture-51

点击Finish。您应该会看到两个项目有错误。

picture-4

这些错误是预料之中的,因为我们的项目不知道 dm Server Target Runtime,而我们的 dm Server Target Runtime 不知道 Spring Integration 包。让我们一个一个地解决问题。首先让 dm Server 知道 Spring Integration,方法是将 Spring Integration 及其依赖的包部署到 dm Server 的存储库中。这是一个非常简单的过程。将 org.springframework.integration-1.0.3.RELEASE.jarorg.springframework.integration.file-1.0.3.RELEASE.jar(我们的示例依赖的两个包)复制到 dm Server 的 repository/bundles/usr 目录中。然后在 STS 的 Server 视图中双击 dm Server 实例 -> 点击 Repository 选项卡,在右上角您会找到一个 Refresh 按钮。点击它,您应该会看到这两个包在 dm Server 的存储库中可用。

picture-6

现在我们需要让我们的 bundle 项目知道新的 Target Runtime。右键单击每个项目 -> Properties -> Target Runtimes -> SpringSource dm Server (Runtime) v1.0

picture-7

现在所有错误都应该消失了。您已准备好测试这些示例

示例

这两个示例基于非常简单和熟悉的生产者/消费者概念。第一个 bundle osgi-inbound 是一个生产者,它允许您生产一个消息,该消息将被发送到一个消息通道。第二个 bundle osgi-outbound 是一个消费者,它将消费 osgi-inbound bundle 放置在通道上的消息,并将消息写入文件。

通过右键单击服务器实例 -> Start 来启动 dm Server

通过简单地将 osgi-inbound 项目拖放到 dm Server 实例上来部署 osgi-inbound。几秒钟后,您应该会看到启动成功的消息

[2009-07-27 21:56:49.040] onnection(5)-172.16.12.1 <SPDE0010I> Deployment of 'org.springframework.integration.samples.osgi.inbound'
version '1.0.3' completed.

然后对 osgi-outbound bundle 执行相同的操作

[2009-07-27 21:58:45.220] onnection(8)-172.16.12.1 <SPDE0010I> Deployment of 'org.springframework.integration.samples.osgi.outbound'
version '1.0.3' completed.

现在您已准备好测试这些 bundle 提供的功能。为了使其更有趣,我们通过 OSGi 控制台启用了命令行接口 (CLI),您可以通过提供命令消息以及要将消息写入的文件名来与 osgi-inbound bundle 交互。您可以通过以下方式连接到 OSGi 控制台

telnet localhost 2401

或者您可以使用 Server 视图的 Server Console 选项卡并输入

siSend "Hello World" hello.txt

然后点击Execute

您将看到以下内容

picture-9

去验证您的消息是否已写入文件。

这个非常简单且微不足道的概念展示了基于 Spring Integration 提供的消息模型,两个系统之间的松耦合集成。然而,在现实世界中,我们在尝试集成两个系统时必须面对的问题之一是这些系统的独立生命周期,其中行为的变化新系统的添加和/或旧系统的生命周期结束是正常的发生。通常,此类变化不仅需要代码更改,还需要在完全重启服务器后重新部署整个单体(例如,EAR、WAR)应用程序。Spring Integration 的 POJO 编程模型非常适合处理这些系统的松耦合特性,其中一个系统的更改很少影响另一个系统。但是它的生命周期动态性如何呢?让我们假设(在我们这个小示例的范围内)关于文件应该写入何处或如何写入的要求已经改变了。无论是“何处”还是“如何”,都是 osgi-outbound bundle 的责任。在正常情况下,对 osgi-outbound bundle 功能的任何更改都需要完全刷新系统(即,重新部署整个系统并重启服务器)。当您的系统仅由两个 bundle 组成时,这可能不是一个大问题。但如果 bundle 数量超过两个呢?仅仅因为消息应该写入的目录发生了变化,或者引入了一个新子系统应该记录每条传入消息,您是否准备好重建和重新部署打包为 WAR 或 EAR 的整个系统?

这就是 OSGi 及其服务层以及最重要的是 OSGi 服务动态性提供巨大帮助的地方。所以让我们接受上述示例需求,看看如何基于扩展当前示例来实现它们。首先,让我们回顾一下 osgi-inbound bundle 的应用程序上下文配置

<osgi:service id="inboundService" ref="inboundChannel"
interface="org.springframework.integration.channel.SubscribableChannel"/>

<integration:publish-subscribe-channel id="inboundChannel"/>

<integration:gateway id="inboundGateway"
service-interface="org.springframework.integration.samples.osgi.inbound.InboundGateway"
default-request-channel="inboundChannel"/>

正如您所见,一个非常简单的配置,它定义了一个网关代理,允许以 POJO 的方式发送消息,该消息将存入配置为发布/订阅通道的入站通道。然而,更有趣的是,该通道已通过 `` 元素作为服务导出到 OSGi 服务注册表,从而允许当前和未来 bundle 之间实现更加松耦合但动态的协作模型。

我们再看看 osgi-outbound bundle 的应用程序上下文配置。

<osgi:reference id="filesIn"
interface="org.springframework.integration.channel.SubscribableChannel"/>

<file:outbound-gateway id="filesOut"
request-channel="filesIn"
directory="${java.io.tmpdir}/spring-integration-samples/output"
delete-source-files="true"/>

此 bundle 的目标是在 osgi-inbound bundle 启动后立即动态订阅其发布的通道,并将消息写入由 `` 元素配置的目录中的文件,从而体现 OSGi 服务层提供的动态性。您可以在此配置中看到,由 osgi-inbound bundle 导出的 'inboundChannel' OSGi 服务现在通过 `` 元素导入。现在,由 OSGi 服务前端的入站通道已准备好在运行时动态接受和/或失去订阅者。由于 OSGi 服务的动态性,我们还可以更新配置或完全重新设计/重新实现 osgi-outbound bundle,而不会影响系统的生产者部分 (osgi-inbound)。所以让我们继续更改文件将写入的目录(确保 dm Server 仍在运行...实际上,在这篇博客期间完全忘记停止它)。

打开 osgi-outbound 项目 -> src -> META-INF -> spring -> osgi-outbound.xml,并在 'directory' 配置中添加一个子目录(在本例中是 'foo')picture-8 保存文件。几秒钟后,您将看到您的 osgi-outbound bundle 已重新部署。打开 OSGi 或 Server 控制台,像之前一样发送另一条消息,看看新文件是否已写入您刚刚指定的目录。希望它成功了 ;)

结论

请记住,虽然在这个简单的示例中我们只处理两个 bundle,但这些类型的生产者/消费者 bundle 本身可能是您系统其他部分的网关,而这些部分本质上是动态的。例如,假设您想收到有关文件写入的电子邮件通知。使用 SI 和 OSGi,您只需创建一个新的 bundle 来代表您子系统的该部分,作为 osgi-inbound bundle 发布的通道服务的消费者,当您不再需要它时 - 通过停止或卸载此消费者来取消订阅,而不会影响您系统的其余部分。事实上,您可以继续尝试开发另一个 bundle 作为 osgi-inbound消费者,或者发挥您的想象力,开发另一个 bundle 来处理 osgi-outbound bundle 写入的文件。

有关更多想法和更复杂的示例,您可能还会喜欢阅读 Spring Integration 团队成员 Iwein Fuld 的这篇文章

最重要的是 - 集成愉快!!!

获取 Spring 时事通讯

通过 Spring 时事通讯保持联系

订阅

先行一步

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

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部