1.   Spring Integration概述

1.1     背景

Spring框架的一个重要主题是控制反转。从广义上来说,Spring处理其上下文中管理的组件的职责。只要组件减轻了职责,它们同时也被简化了。例如,依赖注入降低了定位和创建组件间依赖的耦合性。同样地,面向方面编程通过模块化可重复利用方面,将业务组件和通用的横切面关注点解耦。在这样的情况下,最终的结果是系统更容易测试,理解,维护和扩展。

 

此外,Spring框架和相关工具集提供一个优秀的构建企业级应用的编程模型。这个模型的一致性对开发者非常有益,特别是其基于公认的最佳实践,比如基于接口的编程,尽量使用聚合而不是继承。Spring简化的抽象和功能强大的类库,在增加了系统可测试性和可移植性的同事,有力地促进了开发者的生产力。

 

Spring Integration是Spring项目中秉承其相同目标和原则的新成员。它扩展了Spring的编程模型到消息领域,在Spring已经存在的企业集成支持的基础上,提供了更高级别的抽象。它将控制反转添加到关注点,支持消息驱动架构,例如当特定业务逻辑应该执行时,响应也应该被发送。它支持路由和消息转换,所以不同的传输协议和不同的数据格式能在不影响易测试性的前提下被集成。换句话说,消息和集成关注点都被框架处理,所以业务组件能更好地与基础设施隔离,从而降低开发者所要面对的复杂的集成职责。

 

作为Spring编程模型的扩展,Spring Integration提供了各种的配置选项,包括注解,支持命名空间的XML,通用bean元素的XML,当然也包括直接使用底层API。这些API基于定义好的策略接口和非侵略性的代理适配器。Spring Integration的设计是受在Spring中的通用模式和知名的企业集成模式中的密切联系启发的。企业集成模式是2004年Gregor Hohpe 和Bobby Woolf在Addison Wesley出版社出版的《企业集成模式》一书中描述的。读过这本书的开发者应该能直接地适应Spring Integration的概念和术语。

 

1.2     目标和原则

Spring Integration主要有如下两个目标:

l  提供一个简单的模型来实现复杂的企业集成解决方案

l  为基于Spring的应用添加异步的、消息驱动的行为

l  让Spring用户可以直观的、增量的采用

 

Spring Integration基于两个原则:

l  组件应该松耦合,方便模型化和易测试

l  框架应该强制业务逻辑和集成逻辑的关注点分离

l  扩展点本质上应该是抽象的,而且限定在一个清晰的边界内,来促进可重用性和可移植性

 

1.3     主要组件

纵向地看,一个分层的架构利于关注点的分离,各层间基于接口的契约实现了松耦合。典型地,基于Spring的应用就是这样设计的,Spring框架和工具集提供了一个遵从最佳实践、全栈式开发企业级应用的强大基础。横向地看,消息驱动架构添加了横向视图,虽然这些目标还是相关的。分层架构是一个非常通用和抽象的范式,消息系统非常符合同样抽象的“管道和过滤器”模型。“过滤器”代表任何能够生产和(或)消费消息的组件,“管道”在过滤器间传输消息,所以组件间保持松耦合。值得指出的是,这两个高级范式不是互斥的。其中的消息基础设施支持包装“管道”到契约被定义为接口的层。同样地,“过滤器”一般被管理在逻辑上位于应用系统的服务层之上的层中,其与那些服务在相同的方式下通过接口交互。

 

消息

在Spring Integration中,消息是任何Java对象连同框架处理对象时使用的元数据的一个通用包装。它由负载和头部组成。负载可以是任何类型,头部保存一般的请求信息,例如id,时间戳,过期时间和返回地址。头部也被用来在各种传输协议间传值。比如,从接收到的一个文件创建一个消息时,可以把文件名存储在头部,这些下游的组件就可以使用它。同样地,如果一个消息的内容最终被一个对外接出的Mail适配器发送,各种属性(收件人,发送人,抄送人,主题等)可以被上游组件配置为消息头部值。开发者也可以在头部存储任意的键值对。

 

消息通道

一个消息通道代表“管道和过滤器”架构中的一个“管道”。消息生产者发送消息到通道,消息消费者从通道接收消息。消息通道因此解耦了消息组件,同时也提供了消息拦截和监控的切入点。

 

一个消息通道可能符合点对点模式或者发布-订阅模式。如果是点对点模式的通道,发布到通道中的每个消息,最多只有一个消费者可以接收。如果是发布-订阅模式的通道,则会尝试广播每个消息给其所有的订阅者。Spring Integration支持这两种模式。

鉴于“点对点模式”和“发布订阅模式”定义了每个消息最终有多少消息消费者接收的两种方式,这里有一个重要的考虑:通道是否应该缓冲消息?Spring Integration中,轮询通道(Pollable Channels)具有在一个队列中缓冲消息的能力。缓冲的优势在于它能够调节接入消息流量,从而防止系统负荷过载。然而,正如其名称所示,这也增加了一些复杂性,只有配置了轮询器后,一个消息消费者才能从这个通道中接收消息。另外来说,订阅通道(Subscribable Channel)要求连接它的消费者依从简单的消息驱动模式。Spring Integration中还有多种通道的可用实现,将在第3.2章节“消息通道实现”中详细讨论。

 

消息终端

Spring Integration的主要目标之一是通过控制反转简化企业集成解决方案的开发。这意味着你应该不需要直接实现消息消费者和生产者,更不需要在消息通道中构建和调用发送接收操作的细节。相反地,你只需要关注于你基于普通对象实现的特定领域模型。然后,通过宣告式的配置,你可以“连接”你的领域特定代码到Spring Integration提供的消息基础设施。负责这些连接的代码是消息终端。这并不是说必须直接连接到现有应用的代码。任何现有的企业集成解决方案,都需要一些用于集成相关的代码,例如路由选择和协议转换。其中的一个要点就是实现集成逻辑和业务逻辑关注点的分离。换句话说,作为web应用中的MVC模式,其目标应该是提供一个简单而专用的层,转换接入的请求到服务层调用,然后转换服务层返回值到接出的响应。下一节将讲述处理这些响应的各种消息端点概况,接下来的章节,将为你展示Spring Integration每个宣言式的配置选项是如何提供一个非侵入性的使用方式的。

 

1.4     消息端点

一个消息端点代表“管道和过滤器架构”中的一个“过滤器”。就像前面提到的,端点的主要角色是连接应用代码到消息框架,当然它使用非侵入性的方式。换句话说,应用代码应该完全意识不到消息对象或者消息通道的存在。这就好比MVC模式中的控制器角色。就像控制器处理HTTP请求,消息端点处理消息。而控制器被映射到URL模式,消息端点被映射到消息通道。这两个例子中存在相同的目标:从基础设置中分离应用代码。《企业应用集成》一书中详细地讨论了这些概念及其各种模式。这里我们只概括地描述Spring Integration支持的主要端点类型和它们的角色。本章将提供实例代码并详细阐述。

 

消息转换器

消息转换器负责转换一个消息的内容或结构,并返回翻修改后的消息。最常见的转换器可能是把消息负载从一种格式转换成另一种格式的转换器(例如从XML文档转换成java.lang.String字符串)。同样地,转换器也可以被用于添加、删除和修改消息头中的值。

 

过滤器

消息过滤器最终决定消息是否被发送到输出通道。这简单地依赖于一个布尔型的测试方法,它可以检查消息是否包含特定的负载内容的类型,一个属性值,是否包含消息头等等。如果一个消息被接受,它将被发送到输出通道,否则消息将被丢弃(或者在一个更严格的实现里,应该抛出一个异常信息)。消息过滤器通常和发布订阅通道一起使用,此时多个消费者接收到相同的消息,而在某些条件下使用过滤器可以减少需要处理的消息数量。

 

 

 

注意

应当注意不要混淆“管道和过滤器”架构模式中常说的“过滤器”和在两个通道之间有选择地限制消息流动的特定端点类型。Spring Integration中的端点更接近于“管道和过滤器”架构模式中的“过滤器”:任何组件都可以被连接到消息通道,来发送和(或)接收消息。

 

路由

消息路由负责决定下个消息将由哪些通道接收。典型地,这种决定是基于消息的内容和(或)消息头部中的可用元数据。一个消息路由常常作为动态配置输出通道的一个动态选择,用在消息激活器或是其它的能发送响应消息的端点上。同样地,相对于被动的消息过滤器方式,消息路由提供一个主动的方式被多个订阅者使用,就像上面描述的那样。

 


消息分解器

消息分解器是另外一种类型的消息端点,它负责从一个输入通道中接收一个消息,把消息分解成多个消息,然后把它们发送到相应的输出通道。一个典型的例子就是把一个复合的负载对象分解成一组包含各个子负载的消息。

 

聚合器

集合器基本上是分解器的镜像,也是一种消息端点,它接收多个消息,然后把他们合并成一个单独的消息。事实上,聚合器经常和管道中的分解器一起用来减少消费者数量。技术上来说,聚合器比分解器更复杂,因为它需要维持状态(被聚合的多个消息),决定整组消息何时可用,以及必要时处理超时。此外,在超时的情况下,聚合器需要知道是发送部分的消息,还是丢弃它们到一个单独的通道。Spring Integration提供了可配置的超时处理策略,在超时时发送部分结果,还是发送到收集丢弃消息的通道。

 

服务激活器

服务激活器是一个连接服务实例到消息系统的通用端点。输入消息通道必须被配置,然后如果被调用的服务方法能够返回一个值,说明输出消息通道可能也被提供了。

 

 

 

注意

一个输出通道是可选的,因为每个消息也可以提供其独有的“返回地址”头部信息,这个规则适用于所有的消费者端点。

 

服务激活器调用一些服务对象上的操作,处理请求消息,取出请求消息的负载,以及在必要的时候转换(如果方法不需要一个消息类型的参数)。当服务对象的方法返回一个值时,这个返回值同样地在必要时转换成一个回应消息(如果它还不是一个消息)。这个回应消息被发送到输出通道。如果没有配置输出通道,并且消息的“返回地址”可用,那么它将发送到此地址指定的通道。

 

请求-回应“服务激活器”端点连接到一个目标对象的方法到输入输出消息通道。

 

通道适配器

通道适配器是一个连接消息通道到其他系统或是传输的端点。通道适配器可以是接入或是接出的。典型地,通道适配器可以在消息和其他任何发送到/接收于其他系统(文件、HTTP请求,JMS消息等等)的对象或资源之间做一些映射。依赖于传输,通道适配器也可以构造或是修改消息头的值。Spring Integration提供了一些通道适配器,它们将在接下来的章节讲述。

 

一个接入“通道适配器”端点连接一个源系统到一个消息通道

 

一个接出“通道适配器”端点连接一个消息通道到一个目标系统