|
对于最新稳定版本,请使用 Spring Integration 7.0.0! |
Spring集成框架概述
Spring Integration 是 Spring 编程模型的扩展,以支持众所周知的企业集成模式。它支持基于 Spring 的应用程序中的轻量级消息传递,并通过声明式适配器与外部系统集成。这些适配器相比 Spring 在远程处理、消息发送和调度方面提供了更高层次的抽象。
Spring Integration的主要目标是提供一个简单的企业集成解决方案模型,同时保持对生成可维护、可测试代码至关重要的关注点分离。
春季集成概述
本章为Spring Integration的核心概念和组件提供了高层次介绍。还包括一些编程技巧,帮助你充分利用Spring Integration。
背景
Spring 框架的一个关键主题是控制反转(IoC)。从最广义上讲,这意味着框架代表其上下文中管理的组件来处理责任。组件本身被简化,因为它们被解除了这些责任。例如,依赖注入减轻了组件寻找或创建依赖关系的责任。同样,面向切面编程通过模块化业务组件,将其模块化为可重用的方面,减轻了通用的跨切关注点。在每种情况下,最终结果都是更易于测试、理解、维护和扩展的系统。
此外,Spring 框架和产品组合为构建企业应用提供了全面的编程模型。开发者受益于该模型的一致性,尤其是基于成熟的最佳实践,如对接口编程和优先组合而非继承。Spring 简化的抽象和强大的支持库提升了开发者的生产力,同时提升了测试性和可移植性。
Spring Integration的动机正是基于这些目标和原则。它将Spring编程模型扩展到消息领域,并在Spring现有的企业集成支持基础上,提供更高层次的抽象。它支持消息驱动架构,其中控制反转适用于运行时的关切,比如某些业务逻辑何时运行、响应应发送在哪里。它支持消息的路由和转换,使不同的传输和数据格式能够集成而不影响可测试性。换句话说,消息传递和集成问题由框架处理。业务组件进一步与基础设施隔离,开发者无需承担复杂的集成责任。
作为 Spring 编程模型的扩展,Spring Integration 提供了多种配置选项,包括注释、支持命名空间的 XML、带有通用“豆子”元素的 XML,以及直接使用底层 API。 该API基于明确定义的策略接口和非侵入式委派适配器。 Spring Integration 的设计灵感来自于 Spring 内部常见模式与 Gregor Hohpe 和 Bobby Woolf 在《企业集成模式》中描述的著名模式之间高度亲和力的认识(Addison Wesley, 2004)。 读过那本书的开发者应该会立刻熟悉 Spring Integration 的概念和术语。
目标与原则
春季集成的动机包括以下目标:
-
提供一个简单的模型来实现复杂的企业集成解决方案。
-
促进基于Spring的应用中的异步、消息驱动行为。
-
促进现有 Spring 用户的直观、渐进式采用。
春季集成遵循以下原则:
-
组件应以松耦合方式实现模块化和可测试性。
-
该框架应强制将业务逻辑与集成逻辑之间的关注点分离。
-
扩展点应具有抽象性质(但在明确的边界内),以促进重复使用和可移植性。
主要组成部分
从纵向角度看,分层架构有助于关注点的分离,层间基于接口的契约促进松耦合。 基于Spring的应用程序通常就是这样设计的,而Spring框架和产品组合为遵循企业应用全栈的最佳实践提供了坚实的基础。 以信息驱动的架构增加了横向视角,但这些目标依然具有现实意义。 正如“分层架构”是一个极其通用且抽象的范式,消息系统通常遵循类似抽象的“管道与过滤器”模型。 “过滤器”代表任何能够产生或消耗消息的组件,而“管道”则在过滤器之间传输消息,使组件本身保持松耦合。 需要注意的是,这两种高层次范式并不互斥。 支持“管道”的底层消息基础设施仍应封装在一个合同定义为接口的层中。 同样,“过滤器”本身应在逻辑上位于应用服务层之上的层内管理,通过接口与这些服务交互,方式类似于网页层。
消息
在 Spring Integration 中,消息是任意 Java 对象的通用包装器,结合框架在处理该对象时使用的元数据。 它由有效载荷和头部组成。 有效载荷可以是任何类型,头部包含常见的必要信息,如ID、时间戳、相关ID和返回地址。 头部也用于与连接传输之间的传递值。 例如,从接收到的文件创建消息时,文件名可能会被存储在一个头部中,供下游组件访问。 同样,如果消息内容最终将由发件邮件适配器发送,上游组件可以将各种属性(to、from、cc、subject等)配置为消息头值。 开发者还可以在头部中存储任意的键值对。
消息频道
消息通道代表管道与过滤器架构中的“管道”。 制作人向频道发送消息,消费者接收频道的消息。 因此,消息通道将消息组件解耦,同时也为截获和监控消息提供了便捷的点。
消息通道可以采用点对点或发布-订阅语义。 在点对点信道中,每个发送到信道的消息最多只能接收一个消费者。 而发布订阅频道则尝试向频道内所有订阅者广播每条消息。 Spring Integration 支持这两种模式。
虽然“点对点”和“发布-订阅”定义了最终接收多少消费者的消息选项,但还有另一个重要考虑:信道是否应该缓冲消息? 在Spring Integration中,可轮询通道能够在队列中缓冲消息。 缓冲的优点是允许限制进站消息,从而防止用户过载。 然而,顾名思义,这也增加了一些复杂性,因为消费者只有在配置了轮询器的情况下才能接收该信道的消息。 另一方面,连接到可订阅频道的消费者则是消息驱动的。《消息通道实现》详细讨论了 Spring 集成中可用的多种通道实现。
消息端点
春季集成的主要目标之一是通过控制反转简化企业集成解决方案的开发。 这意味着你无需直接实现消费者和生产者,甚至不必在消息通道上构建消息或调用发送/接收作。 相反,你应该能够专注于基于纯对象的具体领域模型实现。 然后,通过提供声明式配置,你可以将领域特定的代码“连接”到Spring Integration提供的消息基础设施。 负责这些连接的组件是消息端点。 这并不意味着你必须直接连接现有的应用代码。 任何现实世界的企业集成解决方案都需要一定程度的代码,专注于路由和转换等集成问题。 重要的是实现集成逻辑与业务逻辑之间的关注点分离。 换句话说,就像Web应用的模型-视图-控制器(MVC)范式一样,目标应是提供一个薄但专门的层,将入站请求转换为服务层调用,然后将服务层返回值转换为出站回复。 下一节概述了处理这些职责的消息端点类型,接下来的章节中,你可以看到 Spring Integration 的声明式配置选项如何为每种端点提供非侵入式使用方式。
消息端点
消息端点代表了管道与过滤器架构中的“过滤器”。 如前所述,端点的主要作用是将应用代码连接到消息框架,并且以非侵入式方式完成。 换句话说,应用程序代码理想情况下不应感知消息对象或消息通道。 这类似于MVC范式中控制器的角色。 正如控制器处理HTTP请求一样,消息端点处理消息。 正如控制器映射到URL模式,消息端点映射到消息通道。 目标在两种情况下都是一样的:将应用代码与基础设施隔离开来。 这些概念及后续所有模式在《企业集成模式》一书中有详细讨论。 这里,我们仅提供 Spring Integration 支持的主要端点类型及其相关角色的高级描述。 后续章节详细介绍并提供了示例代码及配置示例。
消息转换器
消息变换器负责转换消息的内容或结构并返回修改后的消息。
最常见的变换器类型可能是将消息的有效载荷从一种格式转换为另一种格式(例如从XML转换为java.lang.字符串).
同样,变换器可以添加、删除或修改消息的头部值。
消息过滤器
消息过滤器决定消息是否应传递到输出通道。
这只需要一个布尔测试方法,可以检查特定的有效载荷内容类型、属性值、头部的存在或其他条件。
如果消息被接受,则发送到输出信道。
如果不行,则被放弃(或者,在更严厉的实现中,是例外可能会被扔出去)。
消息过滤器通常与发布-订阅通道结合使用,多个用户可能接收同一消息,并利用过滤器的条件缩小待处理消息的范围。
| 请注意,不要将管道与过滤器架构模式中“过滤器”的通用用法与这种特定端点类型混淆,后者会选择性地缩小两个通道间流动的消息范围。 管道与过滤器的“过滤器”概念更贴近 Spring Integration 的消息端点:任何可以连接到消息通道以发送或接收消息的组件。 |
消息路由器
消息路由器负责决定接下来接收消息的信道(如果有的话)。 通常,决策基于消息内容或消息头部可用的元数据。 消息路由器常作为静态配置输出通道的动态替代方案,替代服务激活器或其他能够发送回复消息的终端。 同样,消息路由器为多用户使用的响应式消息过滤提供了一种主动替代方案,如前所述。
聚合
聚合器基本上是分路器的镜像,是一种消息端点,接收多个消息并将其组合成一条消息。
事实上,聚合器通常是包括分流器在内的下游消费者。
从技术上讲,聚合器比分路器更复杂,因为它需要维护状态(待聚合的消息),决定何时可用完整组消息,并在必要时超时。
此外,在超时情况下,聚合器需要知道是发送部分结果、丢弃还是发送到另一个通道。
Spring 集成提供了相关策略一个发布策略以及可配置的超时设置,如果
超时发送部分结果,以及丢弃通道。
服务激活器
服务激活器是一种通用端点,用于将服务实例连接到消息系统。 输入消息通道必须配置,如果被调用的服务方法能够返回某个值,也可以提供输出消息通道。
| 输出通道是可选的,因为每个消息还可能提供自己的“返回地址”头部。 这条规则同样适用于所有消费者端点。 |
服务激活器会对某个服务对象调用作来处理请求消息,提取请求消息的有效载荷并进行转换(如果方法不期望有消息类型参数)。 每当服务对象的方法返回一个值时,如果该返回值还没有消息类型,也会如有必要被转换为回复消息。 该回复消息会发送到输出信道。 如果没有配置输出信道,回复会发送到消息“返回地址”指定(如果有的话)指定信道。
请求-回复服务激活器端点将目标对象的方法与输入和输出消息通道连接起来。
| 如前所述,在消息频道中,频道可以是可轮询的,也可以是可订阅的。 在前面的图中,这通过“时钟”符号、实心箭头(poll)和虚线箭头(subscribe)表示。 |
通道适配器
通道适配器是一个端点,用于将消息通道连接到其他系统或传输。 通道适配器可以是入站的,也可以是出站的。 通常,通道适配器会在消息与接收或发送到其他系统(文件、HTTP请求、JMS消息等)的对象或资源之间进行某种映射。 根据传输类型,通道适配器还可能填充或提取消息头值。 Spring Integration 提供了若干通道适配器,后续章节将详细介绍。
消息频道.| 消息源可以是可轮询的(例如 POP3)或消息驱动的(例如 IMAP Idle)。 在前述图中,这通过“时钟”符号、实心箭头(poll)和虚线箭头(信息驱动)表示。 |
消息频道目标系统。| 如前所述,频道可以是轮询的,也可以是订阅的。 在前面的图中,这通过“时钟”符号、实心箭头(poll)和虚线箭头(subscribe)表示。 |
端点豆名称
消耗端点(任何具有输入通道)由两个豆子组成,分别是消费者和消息处理者。
消费者会有一个消息处理器的引用,并在消息到达时调用该地址。
请考虑以下 XML 示例:
<int:service-activator id = "someService" ... />
给出上述例子,Beans名称如下:
-
消费者:
某些服务(身份证) -
处理器:
someService.handler
使用企业集成模式(EIP)注释时,名称取决于多个因素。 请考虑以下带注释的POJO示例:
@Component
public class SomeComponent {
@ServiceActivator(inputChannel = ...)
public String someMethod(...) {
...
}
}
给出上述例子,Beans名称如下:
-
消费者:
someComponent.someMethod.serviceActivator -
处理器:
someComponent.someMethod.serviceActivator.handler
从5.0.4版本开始,你可以通过使用@EndpointId注释,如下示例所示:
@Component
public class SomeComponent {
@EndpointId("someService")
@ServiceActivator(inputChannel = ...)
public String someMethod(...) {
...
}
}
给出上述例子,Beans名称如下:
-
消费者:
某些服务 -
处理器:
someService.handler
这@EndpointId由身份证属性与XML配置。
考虑以下带注释豆的例子:
@Configuration
public class SomeConfiguration {
@Bean
@ServiceActivator(inputChannel = ...)
public MessageHandler someHandler() {
...
}
}
给出上述例子,Beans名称如下:
-
消费者:
someConfiguration.someHandler.serviceActivator -
处理器:
某个控者(@Bean名称)
从5.0.4版本开始,你可以通过使用@EndpointId注释,如下示例所示:
@Configuration
public class SomeConfiguration {
@Bean("someService.handler") (1)
@EndpointId("someService") (2)
@ServiceActivator(inputChannel = ...)
public MessageHandler someHandler() {
...
}
}
| 1 | 处理器:someService.handler(豆子的名字) |
| 2 | 消费者:某些服务(端点ID) |
这@EndpointId注释创建了由身份证属性与XML配置,只要你使用附加约定。处理器前往@Bean名字。
有一个特殊情况,会生成第三颗豆子:出于结构原因,如果消息处理器 @Bean不定义摘要回复制作消息处理器,框架将提供的豆子包裹在回复ProducingMessageHandlerWrapper. 该包装器支持请求处理程序的建议处理,并发出正常的“未生成无回复”调试日志消息。它的 bean 名称是 handler bean name plus。包装纸(当存在@EndpointId——否则,它是正常生成的处理程序名称)。
类似地,可轮询消息源会生成两个豆子,即SourcePollingChannelAdapter(SPCA)和消息源.
考虑以下 XML 配置:
<int:inbound-channel-adapter id = "someAdapter" ... />
根据上述XML配置,豆子名称如下:
-
SPCA:
某个适配器(身份证) -
处理器:
someAdapter.source
考虑以下 Java 配置的 POJO 来定义@EndpointId:
@EndpointId("someAdapter")
@InboundChannelAdapter(channel = "channel3", poller = @Poller(fixedDelay = "5000"))
public String pojoSource() {
...
}
给定前面的 Java 配置示例,豆子名称如下:
-
SPCA:
某个适配器 -
处理器:
someAdapter.source
考虑以下 Java 配置,定义一个豆子@EndpointID:
@Bean("someAdapter.source")
@EndpointId("someAdapter")
@InboundChannelAdapter(channel = "channel3", poller = @Poller(fixedDelay = "5000"))
public MessageSource<?> source() {
return () -> {
...
};
}
给出上述例子,Beans名称如下:
-
SPCA:
某个适配器 -
处理器:
someAdapter.source(只要你使用附加的惯例。源前往@Bean名称)
配置和@EnableIntegration
在本文档中,你可以看到对 Spring Integration 流程中声明元素的 XML 命名空间支持的引用。这种支持由一系列命名空间解析器提供,生成合适的 bean 定义以实现特定组件。例如,许多端点由消息处理器豆子和ConsumerEndpointFactoryBean注入处理程序和输入信道名称。
首次遇到 Spring Integration 命名空间元素时,框架会自动声明若干 Beans(任务调度器、隐式通道创建器等)用于支持运行环境。
4.0 版本引入了@EnableIntegration注释,以便注册 Spring Integration 基础设施的 beans(参见 Javadoc)。当仅使用 Java 配置时,需要此注释——例如支持 Spring Boot 或 Spring Integration 消息注释,以及无 XML 集成配置的 Spring Integration Java DSL。 |
这@EnableIntegration当你有一个没有 Spring Integration 组件的父上下文和两个或多个使用 Spring Integration 的子上下文时,注释也很有用。它允许这些常见组件在父上下文中声明一次。
这@EnableIntegration注释将许多基础设施组件与应用上下文关联。特别是,它:
-
注册一些内置的豆子,例如
errorChannel以及其日志处理器,任务调度器对于民调者来说,jsonPathSpEL-函数等。 -
补充了几个
豆工厂后处理实例以增强豆子工厂用于全局和默认集成环境。 -
补充了几个
豆子后处理器实例用于增强、转换和包装特定豆子以实现集成。 -
添加注释处理器以解析消息注释,并在应用上下文中注册其组件。
这@IntegrationComponentScan注释还允许类路径扫描。该注释的作用类似于标准的 Spring 框架@ComponentScan注释,但仅限于Spring Integration特有的组件和注释,而标准Spring Framework组件扫描机制无法覆盖这些。示例请参见@MessagingGateway注解.
这@EnablePublisher注释寄存器出版商注释豆后处理器Bean并配置默认-出版商-通道对于那些@Publisher提供时没有渠道属性。 如果不止一个@EnablePublisher找到注释后,默认通道的值必须相同。 看注释驱动配置,具有@Publisher注解更多信息请见。
这@GlobalChannelInterceptor注释已引入给马克通道拦截者全局通道拦截的豆子。该注释是<文:通道拦截器>XML元素(参见全局通道拦截器配置)。@GlobalChannelInterceptor注释可以在类级层面放置(带有@Component刻板印象注释)或在@Bean以下方法@Configuration类。
无论哪种情况,豆子都必须实现通道拦截者.
从版本5.1开始,全局通道拦截器适用于动态注册的通道——例如通过beanFactory.initializeBean()或者通过集成流上下文当使用 Java DSL 时。
此前,在应用上下文刷新后创建豆子时,不会应用拦截器。
这@IntegrationConverter注释标记转炉,通用转换器或转换器工厂豆子作为候选转换器integrationConversionService.
该注释是<智力:转换器>XML 元素(参见有效载荷类型转换)。
你可以放@IntegrationConverter类级注释(带有@Component刻板印象注释)或在@Bean以下方法@Configuration类。
有关消息注释的更多信息,请参见注释支持。
编程考虑
你应该尽可能使用普通的 Java 对象(POJO),只有在绝对必要时才在代码中暴露框架。 更多信息请参见POJO方法调用。
如果你真的把这个框架暴露给你的课程,尤其是在应用启动阶段,有一些需要考虑的因素:
-
如果你的组件是
应用上下文感知,通常你不应该使用应用上下文在setApplicationContext()方法。 相反,存储一个引用,并将此类使用推迟到上下文生命周期的后期。 -
如果你的组件是
初始化Bean或用途@PostConstruct方法,不要发送来自这些初始化方法的任何消息。 调用这些方法时,应用上下文尚未初始化,发送此类消息很可能会失败。 如果你需要在启动时发送消息,就实现ApplicationListener并等待ContextRefreshedEvent. 或者,实现SmartLifecycle把你的豆子放在晚期阶段,然后发送消息开始()方法。
使用封装(例如遮蔽)罐子时的注意事项
Spring Integration 通过使用 Spring Framework 的春季工厂装载多个集成配置初始化器类。
这包括-核心还有其他一些,包括-http和-JMX.
该过程的信息存储在META-INF/spring.factories把文件放进每个罐子里。
一些开发者更喜欢使用知名工具(如 Apache Maven Shade Plugin)将应用程序和所有依赖重新打包到一个 jar 中。
默认情况下,shade插件不会合并Spring。工厂文件,在生成阴影罐时。
此外Spring。工厂其他元步兵文件(Spring。控者和spring.schemas)用于XML配置。
这些文件也需要合并。
Spring Boot 的可执行罐机制采用了不同的方式,它将罐子嵌套起来,从而保留每个罐子Spring。工厂类路径上的文件。
所以,使用 Spring Boot 应用时,只要使用默认的可执行 jar 格式,就不需要更多作。 |
即使你不使用 Spring Boot,也可以使用 Boot 提供的工具,通过为上述文件添加变换器来增强阴影插件。 以下示例展示了如何配置该插件:
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
<createDependencyReducedPom>true</createDependencyReducedPom>
</configuration>
<dependencies>
<dependency> (1)
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers> (2)
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
具体说来
| 1 | 添加Spring-boot-Maven-插件作为一种依赖。 |
| 2 | 配置转换器。 |
你可以添加一个属性${spring.boot.version}或者使用明确的版本。
编程技巧与技巧
本节记录了一些最大化 Spring 集成功能的方法。
XML 模式
使用 XML 配置时,为了避免出现错误的模式验证错误,应使用“支持 Spring 智能开发环境”的集成开发环境,如 Spring 工具套件(STS)、带有 Spring IDE 插件的 Eclipse 或 IntelliJ IDEA。
这些IDE知道如何从类路径中解析正确的XML模式(通过使用META-INF/spring.schemas将文件放入罐子中)。
使用STS或Eclipse配合插件时,必须启用春季项目自然在项目上。
某些遗留模块(1.0版本中存在的)托管在互联网上的模式是1.0版本,出于兼容性考虑。 如果你的IDE使用这些模式,你很可能会看到错误。
这些在线模式中的每个都带有类似以下警告:
|
该模式适用于 Spring Integration Core 1.0 版本。 我们无法更新到当前的模式,因为那样会导致使用1.0.3及以下版本的应用程序受损。 在后续版本中,“无版本化”模式由类路径解析并从jar中获取。 请参阅GitHub: |
受影响的模块包括
-
核心(spring-integration.xsd) -
文件 -
http -
JMS -
邮件 -
安全 -
流 -
WS -
XML
查找 Java 和 DSL 配置的类名
通过XML配置和Spring集成命名空间支持,XML解析器隐藏目标豆的声明和连接方式。 对于 Java 配置,理解目标终端用户应用的框架 API 非常重要。
实施EIP的一等公民有消息,渠道和端点(参见本章前方的主要组成部分)
它们的实现(合同)包括:
前两个工具足够简单,易于理解如何实现、配置和使用。 最后一个值得更多关注
这摘要终点在 Spring 框架中广泛应用于不同的组件实现。
其主要实现包括:
-
EventDrivenConsumer当我们订阅 a订阅频道去监听信息。 -
民调消费者,用于我们对来自 的消息进行轮询Pollable频道.
当你使用消息注释或 Java DSL 时,你无需担心这些组件,因为框架会自动生成带有相应注释的组件,豆子后处理器实现。
手动组装组件时,你应该使用ConsumerEndpointFactoryBean以帮助确定目标摘要终点消费者实现以创建,基于提供的输入通道财产。
另一方面,ConsumerEndpointFactoryBean在框架中,另一位一等公民的代表——org.springframework.messaging.MessageHandler.
该接口的实现目标是处理端点从信道中消耗的消息。
Spring 集成中的所有 EIP 组件包括消息处理器实现(例如,聚合消息处理器,消息变换处理程序,摘要消息分流器,以及其他。
目标协议出站适配器(文件写入消息处理器,HttpRequestExecutingMessageHandler,摘要MqttMessageHandler,以及其他)也都是消息处理器实现。
当你开发带有 Java 配置的 Spring 集成应用时,应该了解 Spring 集成模块,找到合适的配置消息处理器用于@ServiceActivator配置。
例如,要发送 XMPP 消息(参见 XMPP 支持),你应该配置如下内容:
@Bean
@ServiceActivator(inputChannel = "input")
public MessageHandler sendChatMessageHandler(XMPPConnection xmppConnection) {
ChatMessageSendingMessageHandler handler = new ChatMessageSendingMessageHandler(xmppConnection);
DefaultXmppHeaderMapper xmppHeaderMapper = new DefaultXmppHeaderMapper();
xmppHeaderMapper.setRequestHeaderNames("*");
handler.setHeaderMapper(xmppHeaderMapper);
return handler;
}
这消息处理器实现代表消息流的出站和处理部分。
入站消息流端有自己的组成部分,分为轮询和监听行为。
监听(消息驱动)组件简单,通常只需一个目标类实现即可准备好
产出信息。
监听组件可以是单向的MessageProducerSupport实现,(例如摘要MqttMessageDrivenChannelAdapter和ImapIdleChannelAdapter)或请求-回复MessagingGatewaySupport实现(例如AmqpInboundGateway和摘要WebServiceInboundGateway).
轮询入站端点适用于那些不提供监听器 API 或不为 这种行为包括任何基于文件的协议(如FTP)、任何数据库(关系数据库管理系统或NoSQL)等。
这些入站端点由两个组成部分组成:轮询器配置,用于周期性启动轮询任务,以及消息源类,用于读取目标协议的数据并为下游集成流程生成消息。轮询器配置的第一类是SourcePollingChannelAdapter. 又多了一次摘要终点实现,尤其是用于轮询以启动集成流程。通常,对于消息注释或 Java DSL 来说,你不必担心这个类。框架会生成一个基于@InboundChannelAdapter配置或Java DSL构建器规范。
消息源组件对目标应用开发更为重要,且它们都实现了消息源接口(例如,MongoDb消息源和摘要推特消息来源). 考虑到这一点,我们用JDBC从RDBMS表读取数据的配置可以如下:
@Bean
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixedDelay="5000"))
public MessageSource<?> storedProc(DataSource dataSource) {
return new JdbcPollingChannelAdapter(dataSource, "SELECT * FROM foo where status = 0");
}
你可以在特定的 Spring Integration 模块中找到目标协议所需的所有入站和出站类(大多数情况下,在相应的包中)。例如,Spring-integration-websocket适配器有:
-
o.s.i.websocket.inbound.WebSocketInboundChannelAdapter:实现MessageProducerSupport用于监听套接字上的帧并向信道发送消息。 -
o.s.i.websocket.outbound.WebSocket OutboundMessageHandler:单程摘要消息处理器实现了将收到的消息转换为相应帧并通过Websocket发送。
如果你熟悉从 4.3 版本开始的 Spring Integration XML 配置,我们会在XSD 元素定义中提供关于哪些目标类用于为适配器或网关声明 Beans 的信息,如下示例所示:
<xsd:element name="outbound-async-gateway">
<xsd:annotation>
<xsd:documentation>
Configures a Consumer Endpoint for the 'o.s.i.amqp.outbound.AsyncAmqpOutboundGateway'
that will publish an AMQP Message to the provided Exchange and expect a reply Message.
The sending thread returns immediately; the reply is sent asynchronously; uses 'AsyncRabbitTemplate.sendAndReceive()'.
</xsd:documentation>
</xsd:annotation>
POJO 方法调用
正如《编程考虑》中所述,我们建议采用POJO编程风格,如下示例所示:
@ServiceActivator
public String myService(String payload) { ... }
在这种情况下,框架提取字符串payload,调用你的方法,并将结果包裹成消息发送给流程中的下一个组件(原始头部被复制到新消息中)。事实上,如果你使用XML配置,甚至不需要@ServiceActivator注释,如下对对示例所示:
<int:service-activator ... ref="myPojo" method="myService" />
public String myService(String payload) { ... }
你可以省略方法属性,只要类上的公共方法没有歧义。
你也可以在 POJO 方法中获取头部信息,如下示例所示:
@ServiceActivator
public String myService(@Payload String payload, @Header("foo") String fooHeader) { ... }
你也可以取消消息属性的引用,如下示例所示:
@ServiceActivator
public String myService(@Payload("payload.foo") String foo, @Header("bar.baz") String barbaz) { ... }
由于有各种 POJO 方法调用,5.0 之前的版本使用 SpEL(Spring 表达式语言)来调用 POJO 方法。SpEL(即使是解释型)通常对这些作来说“足够快”,相较于方法中通常完成的工作。然而,从 5.0 版本开始,org.springframework.messaging.handler.invocation.InvocableHandlerMethod尽可能默认使用。这种技术通常比解释型 SpEL 执行更快,并且与其他 Spring 消息项目保持一致。 这InvocableHandlerMethod类似于Spring MVC中调用控制器方法的技术。使用SpEL时,仍有某些方法始终被调用。例如如前所述,带有去引用属性的注释参数。这是因为SpEL具备导航属性路径的能力。
可能还有一些我们未考虑的角落案例,也无法处理InvocableHandlerMethod实例。 因此,在这种情况下,我们会自动回归使用特殊语言。
如果你愿意,也可以设置你的 POJO 方法,使其始终使用 SpEL,并且使用SpelInvoker注释,如下示例所示:
@UseSpelInvoker(compilerMode = "IMMEDIATE")
public void bar(String bar) { ... }
如果编译器模式省略了性质,即spring.expression.compiler.mode系统属性决定了编译器的模式。有关编译后的 SpEL 的更多信息,请参见 SpEL 编译。