配置

配置

Spring Integration 提供了许多配置选项。 您选择哪个选项取决于您的特定需求以及您喜欢在哪个级别工作。 与一般的 Spring 框架一样,您可以混合和匹配各种技术以适应手头的问题。 例如,您可以为大多数配置选择基于 XSD 的命名空间,并将其与使用注释配置的少数对象组合在一起。 两者尽可能提供一致的命名。 XSD 模式定义的 XML 元素与注释的名称匹配,并且这些 XML 元素的属性与注释属性的名称匹配。 您也可以直接使用 API,但我们希望大多数开发人员选择更高级别的选项之一,或者选择基于命名空间和注释驱动的配置的组合。spring-doc.cadn.net.cn

命名空间支持

您可以使用直接映射到企业集成的术语和概念的 XML 元素来配置 Spring Integration 组件。 在许多情况下,元素名称与《企业集成模式》一书中的元素名称相匹配。spring-doc.cadn.net.cn

要在 Spring 配置文件中启用 Spring Integration 的核心命名空间支持,请在顶级“bean”元素中添加以下命名空间引用和模式映射:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/integration
           https://www.springframework.org/schema/integration/spring-integration.xsd">

(我们强调了 Spring Integration 特有的行。spring-doc.cadn.net.cn

您可以在“xmlns:”之后选择任何名称。 我们使用int(集成的缩写)为了清楚起见,但您可能更喜欢另一个缩写。 另一方面,如果您使用 XML 编辑器或 IDE 支持,则自动完成的可用性可能会说服您保留较长的名称以清楚起见。 或者,您可以创建使用 Spring Integration 模式作为主命名空间的配置文件,如以下示例所示:spring-doc.cadn.net.cn

<beans:beans xmlns="http://www.springframework.org/schema/integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/integration
           https://www.springframework.org/schema/integration/spring-integration.xsd">

(我们强调了 Spring Integration 特有的行。spring-doc.cadn.net.cn

使用此替代方案时,Spring Integration元素不需要前缀。 另一方面,如果在同一配置文件中定义通用 Spring bean,则 bean 元素需要前缀 (<beans:bean …​/>). 由于通常将配置文件本身模块化(基于责任或架构层)是一个好主意,因此您可能会发现在以集成为中心的配置文件中使用后一种方法是合适的,因为在这些文件中很少需要通用 Bean。 出于本文档的目的,我们假设集成命名空间是主要命名空间。spring-doc.cadn.net.cn

Spring Integration 提供了许多其他命名空间。 事实上,提供命名空间支持的每种适配器类型(JMS、文件等)都在单独的模式中定义其元素。 为了使用这些元素,请使用xmlns条目和相应的schemaLocation映射。 例如,以下根元素显示了其中几个命名空间声明:spring-doc.cadn.net.cn

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:int="http://www.springframework.org/schema/integration"
  xmlns:int-file="http://www.springframework.org/schema/integration/file"
  xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
  xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
  xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration
    https://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/file
    https://www.springframework.org/schema/integration/file/spring-integration-file.xsd
    http://www.springframework.org/schema/integration/jms
    https://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
    http://www.springframework.org/schema/integration/mail
    https://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd
    http://www.springframework.org/schema/integration/ws
    https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
 ...
</beans>

本参考手册在相应章节中提供了各种元素的具体示例。 在这里,要识别的主要内容是每个命名空间 URI 和架构位置的命名一致性。spring-doc.cadn.net.cn

配置任务计划程序

在 Spring Integration 中,ApplicationContext起着消息总线的核心作用,您只需要考虑几个配置选项。 首先,您可能想控制中央TaskScheduler实例。 您可以通过提供名为taskScheduler. 这也被定义为一个常量,如下所示:spring-doc.cadn.net.cn

IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME

默认情况下,Spring Integration 依赖于ThreadPoolTaskScheduler,如 Spring Framework 参考手册的 任务执行和调度 部分所述。 该默认值TaskScheduler使用包含 10 个线程的池自动启动,但请参阅全局属性。 如果您提供自己的TaskScheduler实例,您可以将 'autoStartup' 属性设置为false或提供您自己的池大小值。spring-doc.cadn.net.cn

当轮询使用者在其配置中提供显式任务执行器引用时,处理程序方法的调用发生在该执行器的线程池中,而不是主调度程序池中。 但是,当未为端点的轮询器提供任务执行器时,它将由主调度程序的线程之一调用。spring-doc.cadn.net.cn

不要在轮询器线程上运行长时间运行的任务。 请改用任务执行器。 如果有很多轮询终结点,则可能会导致线程匮乏,除非增加池大小。 此外,轮询使用者具有默认值receiveTimeout一秒钟。 由于轮询器线程在此期间会阻塞,因此我们建议您在存在许多此类端点时使用任务执行器,以避免饥饿。 或者,您可以减少receiveTimeout.
如果端点的输入通道是基于队列的(即可轮询的)通道之一,则该端点是轮询使用者。 事件驱动的消费者是那些具有调度器而不是队列的输入通道的消费者(换句话说,它们是可订阅的)。 此类端点没有轮询器配置,因为它们的处理程序是直接调用的。

在 JEE 容器中运行时,您可能需要使用 Spring 的TimerManagerTaskScheduler,如此处所述,而不是默认的taskScheduler. 为此,请为您的环境定义一个具有适当 JNDI 名称的 Bean,如以下示例所示:spring-doc.cadn.net.cn

<bean id="taskScheduler" class="org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler">
    <property name="jndiName" value="tm/MyTimerManager" />
    <property name="resourceRef" value="true" />
</bean>
当自定义TaskScheduler在应用程序上下文中配置(如上所述DefaultManagedTaskScheduler),建议为其提供MessagePublishingErrorHandler (integrationMessagePublishingErrorHandlerbean)能够处理异常ErrorMessage`s sent to the error channel, as is done with the default `TaskScheduler框架提供的 bean。

另请参阅错误处理以获取更多信息。spring-doc.cadn.net.cn

全局属性

可以通过在类路径上提供属性文件来覆盖某些全局框架属性。spring-doc.cadn.net.cn

默认属性可以在org.springframework.integration.context.IntegrationProperties类。 以下列表显示了默认值:spring-doc.cadn.net.cn

spring.integration.channels.autoCreate=true (1)
spring.integration.channels.maxUnicastSubscribers=0x7fffffff (2)
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff (3)
spring.integration.taskScheduler.poolSize=10 (4)
spring.integration.messagingTemplate.throwExceptionOnLateReply=false (5)
spring.integration.readOnly.headers= (6)
spring.integration.endpoints.noAutoStartup= (7)
spring.integration.channels.error.requireSubscribers=true (8)
spring.integration.channels.error.ignoreFailures=true (9)
1 当为true时,input-channel实例自动声明为DirectChannel实例,如果未在应用程序上下文中显式找到。
2 设置允许的默认订阅者数,例如DirectChannel. 它可用于避免无意中将多个端点订阅到同一通道。 您可以通过将max-subscribers属性。
3 此属性提供允许的默认订阅者数,例如PublishSubscribeChannel. 它可用于避免无意中订阅超过同一通道的预期数量的端点。 您可以通过将max-subscribers属性。
4 默认值中可用的线程数taskScheduler豆。 请参阅配置任务计划程序
5 什么时候true,当网关不期望回复时(因为发送线程已超时或已收到回复),到达网关应答通道的消息会抛出异常。
6 不应填充到的以逗号分隔的邮件头名称列表Message标头复制作期间的实例。 该列表由DefaultMessageBuilderFactorybean 并传播到IntegrationMessageHeaderAccessor实例(请参阅MessageHeaderAccessor应用程序接口) 用于通过MessageBuilder(参见MessageBuilder辅助类). 默认情况下,只有MessageHeaders.IDMessageHeaders.TIMESTAMP在消息构建期间不会被复制。 从 4.3.2 版本开始。
7 以逗号分隔的列表AbstractEndpointbean 名称模式 (xxx*,xxx,*xxxxxx*yyy),不应在应用程序启动期间自动启动。 您可以稍后通过Control Bus(参见控制总线),通过它们与SmartLifecycleRoleController(请参阅端点角色),或通过Lifecycle豆子注射。 您可以通过指定auto-startupXML 注释或autoStartupannotation 属性或通过调用AbstractEndpoint.setAutoStartup()在 bean 定义中。 从 4.3.12 版本开始。
8 一个布尔标志,用于指示默认全局errorChannel必须配置requireSubscribers选择。 从 5.4.3 版本开始。 有关详细信息,请参阅错误处理
9 一个布尔标志,用于指示默认全局errorChannel必须忽略分派错误并将消息传递给下一个处理程序。 从 5.5 版本开始。

可以通过添加/META-INF/spring.integration.properties文件添加到类路径或IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAMEbean 的org.springframework.integration.context.IntegrationProperties实例。 您不需要提供所有属性,只需提供要覆盖的属性。spring-doc.cadn.net.cn

从版本 5.1 开始,所有合并的全局属性都会在应用程序上下文启动后打印在日志中,当DEBUG逻辑级别已打开org.springframework.integration类别。 输出如下所示:spring-doc.cadn.net.cn

Spring Integration global properties:

spring.integration.endpoints.noAutoStartup=fooService*
spring.integration.taskScheduler.poolSize=20
spring.integration.channels.maxUnicastSubscribers=0x7fffffff
spring.integration.channels.autoCreate=true
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff
spring.integration.readOnly.headers=
spring.integration.messagingTemplate.throwExceptionOnLateReply=true

注释支持

除了用于配置消息端点的 XML 命名空间支持外,您还可以使用注释。 首先,Spring Integration 提供了类级@MessageEndpoint作为刻板印象注释,这意味着它本身使用 Spring 的@Component注释,因此被 Spring 的组件扫描自动识别为 bean 定义。spring-doc.cadn.net.cn

更重要的是各种方法级注解。 它们表示带注释的方法能够处理消息。 以下示例演示了类级和方法级注解:spring-doc.cadn.net.cn

@MessageEndpoint
public class FooService {

    @ServiceActivator
    public void processMessage(Message message) {
        ...
    }
}

方法“处理”消息的确切含义取决于特定的注释。 Spring Integration 中可用的注释包括:spring-doc.cadn.net.cn

如果将 XML 配置与注释结合使用,则@MessageEndpoint不需要注释。 如果要从ref属性<service-activator/>元素,则只能提供方法级注解。 在这种情况下,即使<service-activator/>元素。

在大多数情况下,带注释的处理程序方法不应要求Messagetype 作为其参数。 相反,方法参数类型可以与消息的有效负载类型匹配,如以下示例所示:spring-doc.cadn.net.cn

public class ThingService {

    @ServiceActivator
    public void bar(Thing thing) {
        ...
    }

}

当方法参数应从MessageHeaders,另一种选择是使用 parameter-level@Header注解。 通常,使用 Spring Integration 注释 Comments 的方法可以接受Message本身、消息有效负载或标头值(@Header) 作为参数。 事实上,该方法可以接受组合,如以下示例所示:spring-doc.cadn.net.cn

public class ThingService {

    @ServiceActivator
    public void otherThing(String payload, @Header("x") int valueX, @Header("y") int valueY) {
        ...
    }

}

您还可以使用@Headers注释,将所有消息头作为Map,如以下示例所示:spring-doc.cadn.net.cn

public class ThingService {

    @ServiceActivator
    public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
        ...
    }

}
注释的值也可以是 SpEL 表达式(例如someHeader.toUpperCase()),当您希望在注入标头值之前作标头值时,这很有用。 它还提供了一个可选的required属性,用于指定属性值是否必须在标头中可用。 的默认值required属性是true.

对于其中几个注释,当消息处理方法返回非空值时,端点会尝试发送回复。 这在两个配置选项(命名空间和注释)中是一致的,因为使用此类端点的输出通道(如果可用),并且REPLY_CHANNELmessage header 值用作回退。spring-doc.cadn.net.cn

终结点上的输出通道和回复通道消息标头的组合启用了管道方法,其中多个组件具有输出通道,最终组件允许将回复消息转发到回复通道(如原始请求消息中指定)。 换句话说,最终组件取决于原始发送方提供的信息,因此可以动态支持任意数量的客户端。 这是返回地址模式的示例。

除了此处显示的示例外,这些注释还支持inputChanneloutputChannel属性,如以下示例所示:spring-doc.cadn.net.cn

@Service
public class ThingService {

    @ServiceActivator(inputChannel="input", outputChannel="output")
    public void otherThing(String payload, @Headers Map<String, Object> headerMap) {
        ...
    }

}

处理这些注释会创建与相应的 XML 组件相同的 bean——AbstractEndpointinstances 和MessageHandler实例(或MessageSource入站通道适配器的实例)。 看注释@Bean方法. Bean 名称是从以下模式生成的:[componentName].[methodName].[decapitalizedAnnotationClassShortName]. 在前面的示例中,bean 名称为thingService.otherThing.serviceActivator对于AbstractEndpoint和相同的名称,但有一个额外的.handler (.source) 后缀MessageHandler (MessageSource)豆。 可以使用@EndpointId注释以及这些消息传递注释。 这MessageHandler实例 (MessageSource实例)也有资格通过消息历史记录进行跟踪。spring-doc.cadn.net.cn

从 4.0 版开始,所有消息传递注释都提供SmartLifecycle选项 (autoStartupphase) 以允许对应用程序上下文初始化进行端点生命周期控制。 它们默认为true0分别。 要更改端点的状态(例如start()stop()),您可以使用BeanFactory(或自动布线)并调用方法。 或者,您可以将命令消息发送到Control Bus(请参阅控制总线)。 出于这些目的,您应该使用beanName前段所述。spring-doc.cadn.net.cn

在解析上述注释(当未配置特定通道 bean 时)和相应的消费者端点后自动创建的通道在上下文初始化结束时被声明为 bean。这些 bean 可以在其他服务中自动连接,但必须使用@Lazy注释,因为在正常的自动布线处理期间,定义通常尚不可用。spring-doc.cadn.net.cn

@Autowired
@Lazy
@Qualifier("someChannel")
MessageChannel someChannel;
...

@Bean
Thing1 dependsOnSPCA(@Qualifier("someInboundAdapter") @Lazy SourcePollingChannelAdapter someInboundAdapter) {
    ...
}

从 6.0 版开始,所有消息传递注释都是@Repeatable现在,可以在同一服务方法上声明多个相同类型的终结点,其含义是创建与重复这些注释一样多的端点:spring-doc.cadn.net.cn

@Transformer(inputChannel = "inputChannel1", outputChannel = "outputChannel1")
@Transformer(inputChannel = "inputChannel2", outputChannel = "outputChannel2")
public String transform(String input) {
    return input.toUpperCase();
}

使用@Poller注解

在 Spring Integration 4.0 之前,消息传递注释要求inputChannel是对SubscribableChannel. 为PollableChannel实例,则<int:bridge/>元素来配置<int:poller/>并使复合端点成为PollingConsumer. 4.0 版引入了@Poller注释以允许配置poller属性,如以下示例所示:spring-doc.cadn.net.cn

public class AnnotationService {

    @Transformer(inputChannel = "input", outputChannel = "output",
        poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
    public String handle(String payload) {
        ...
    }
}

@Poller注释仅提供简单的PollerMetadata选项。 您可以配置@Poller注释的属性 (maxMessagesPerPoll,fixedDelay,fixedRatecron)替换为属性占位符。此外,从版本 5.1 开始,receiveTimeout选项PollingConsumers 也提供了。如果需要提供更多的轮询选项(例如transaction,advice-chain,error-handler等),您应该配置PollerMetadata作为通用 bean,并将其 bean 名称用作@Pollervalue属性。 在这种情况下,不允许使用其他属性(必须在PollerMetadatabean)。注意,如果inputChannel是一个PollableChannel和没有@Poller已配置,默认PollerMetadata(如果它存在于应用程序上下文中)。要使用@Configuration注解,请使用类似于以下示例的代码:spring-doc.cadn.net.cn

@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
    PollerMetadata pollerMetadata = new PollerMetadata();
    pollerMetadata.setTrigger(new PeriodicTrigger(10));
    return pollerMetadata;
}

以下示例显示如何使用默认轮询器:spring-doc.cadn.net.cn

public class AnnotationService {

    @Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
    public String handle(String payload) {
        ...
    }
}

以下示例演示如何使用命名轮询器:spring-doc.cadn.net.cn

@Bean
public PollerMetadata myPoller() {
    PollerMetadata pollerMetadata = new PollerMetadata();
    pollerMetadata.setTrigger(new PeriodicTrigger(1000));
    return pollerMetadata;
}

以下示例显示了使用默认轮询器的终结点:spring-doc.cadn.net.cn

public class AnnotationService {

    @Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
                           poller = @Poller("myPoller"))
    public String handle(String payload) {
         ...
    }
}

从 4.3.3 版本开始,@Poller注释具有errorChannel属性,以便更轻松地配置底层MessagePublishingErrorHandler. 此属性的作用与error-channel<poller>XML 组件。 有关详细信息,请参阅终结点命名空间支持spring-doc.cadn.net.cn

poller()属性与reactive()属性。 有关详细信息,请参阅下一节。spring-doc.cadn.net.cn

@Reactive注解

ReactiveStreamsConsumer自 5.0 版以来一直存在,但仅当端点的输入通道为FluxMessageChannel(或任何org.reactivestreams.Publisher实现)。 从 5.3 版开始,当目标消息处理程序为ReactiveMessageHandler独立于输入通道类型。 这@Reactive子注释(类似于上面提到的@Poller) 已为从 5.5 版开始的所有消息传递注释引入。 它接受可选的Function<? super Flux<Message<?>>, ? extends Publisher<Message<?>>>bean 引用,并且独立于输入通道类型和消息处理程序,将目标端点转换为ReactiveStreamsConsumer实例。 该函数从Flux.transform()运算符来应用一些自定义 (publishOn(),doOnNext(),log(),retry()等等)在来自输入通道的反应流源上。spring-doc.cadn.net.cn

以下示例演示如何将发布线程从输入通道更改为独立于最终订阅者和生产者DirectChannel:spring-doc.cadn.net.cn

@Bean
public Function<Flux<?>, Flux<?>> publishOnCustomizer() {
    return flux -> flux.publishOn(Schedulers.parallel());
}

@ServiceActivator(inputChannel = "directChannel", reactive = @Reactive("publishOnCustomizer"))
public void handleReactive(String payload) {
    ...
}

reactive()属性与poller()属性。 看使用@Poller注解反应流支持了解更多信息。spring-doc.cadn.net.cn

使用@InboundChannelAdapter注解

4.0 版引入了@InboundChannelAdapter方法级注释。它会产生一个SourcePollingChannelAdapter基于MethodInvokingMessageSource对于带注释的方法。此注释是<int:inbound-channel-adapter>XML 组件,并且具有相同的限制:方法不能有参数,返回类型不得为void. 它有两个属性:value(所需的MessageChannelbean name) 和poller(可选的@Poller注释,如前所述)。如果您需要提供一些MessageHeaders,请使用Message<?>返回类型,并使用MessageBuilder构建Message<?>. 使用MessageBuilder允许您配置MessageHeaders. 以下示例演示如何使用@InboundChannelAdapter注解:spring-doc.cadn.net.cn

@InboundChannelAdapter("counterChannel")
public Integer count() {
    return this.counter.incrementAndGet();
}

@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000"))
public String foo() {
    return "foo";
}

4.3 版引入了channel别名valueannotation 属性,以提供更好的源代码可读性。此外,目标MessageChannelbean 在SourcePollingChannelAdapter通过提供的名称(由outputChannelName选项)在第一个receive()调用,而不是在初始化阶段。它允许“后期绑定”逻辑:目标MessageChannelbean 的创建和注册时间晚于@InboundChannelAdapter解析阶段。spring-doc.cadn.net.cn

第一个示例要求在应用程序上下文中的其他地方声明了默认轮询器。spring-doc.cadn.net.cn

使用@MessagingGateway注解spring-doc.cadn.net.cn

使用@IntegrationComponentScan注解

标准的 Spring 框架@ComponentScan注释不会扫描接口的构造型@Component附注。 为了克服此限制并允许配置@MessagingGateway(参见@MessagingGateway注解),我们引入了@IntegrationComponentScan机制。 此注释必须与@Configuration注释并自定义以定义其扫描选项, 如basePackagesbasePackageClasses. 在这种情况下,所有发现的接口都用@MessagingGateway被解析并注册为GatewayProxyFactoryBean实例。 所有其他基于类的组件都由标准解析@ComponentScan.spring-doc.cadn.net.cn

消息传递元注释

从 V4.0 开始,所有消息传递注释都可以配置为元注释,并且所有用户定义的消息传递注释都可以定义相同的属性来覆盖其默认值。 此外,元注释可以分层配置,如以下示例所示:spring-doc.cadn.net.cn

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput")
public @interface MyServiceActivator {

    String[] adviceChain = { "annAdvice" };
}

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator
public @interface MyServiceActivator1 {

    String inputChannel();

    String outputChannel();
}
...

@MyServiceActivator1(inputChannel = "inputChannel", outputChannel = "outputChannel")
public Object service(Object payload) {
   ...
}

分层配置元注释允许用户为各种属性设置默认值,并允许将框架 Java 依赖项隔离到用户注释,从而避免在用户类中使用它们。 如果框架找到具有具有框架元注释的用户注释的方法,则将其视为直接使用框架注释注释该方法。spring-doc.cadn.net.cn

注释@Bean方法

从 4.0 版开始,您可以在@Bean方法定义@Configuration类,以基于 bean(而不是方法)生成消息端点。 当以下情况时,它很有用@Bean定义是“开箱即用”MessageHandler实例 (AggregatingMessageHandler,DefaultMessageSplitter等),Transformer实例 (JsonToObjectTransformer,ClaimCheckOutTransformer等),以及MessageSource实例 (FileReadingMessageSource,RedisStoreMessageSource等)。 以下示例演示如何将消息传递注释与@Bean附注:spring-doc.cadn.net.cn

@Configuration
@EnableIntegration
public class MyFlowConfiguration {

    @Bean
    @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
    public MessageSource<String> consoleSource() {
        return CharacterStreamReadingMessageSource.stdin();
    }

    @Bean
    @Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
    public ObjectToMapTransformer toMapTransformer() {
        return new ObjectToMapTransformer();
    }

    @Bean
    @ServiceActivator(inputChannel = "httpChannel")
    public HttpRequestExecutingMessageHandler httpHandler() {
    HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("https://foo/service");
        handler.setExpectedResponseType(String.class);
        handler.setOutputChannelName("outputChannel");
        return handler;
    }

    @Bean
    @ServiceActivator(inputChannel = "outputChannel")
    public LoggingHandler loggingHandler() {
        return new LoggingHandler("info");
    }

}

5.0 版引入了对@Bean注释为@InboundChannelAdapter返回java.util.function.Supplier,它可以生成 POJO 或Message. 以下示例演示如何使用该组合:spring-doc.cadn.net.cn

@Configuration
@EnableIntegration
public class MyFlowConfiguration {

    @Bean
    @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
    public Supplier<String> pojoSupplier() {
        return () -> "foo";
    }

    @Bean
    @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
    public Supplier<Message<String>> messageSupplier() {
        return () -> new GenericMessage<>("foo");
    }
}

元注释规则适用于@Bean方法(@MyServiceActivator前面描述的注释可以应用于@Bean定义)。spring-doc.cadn.net.cn

当您在消费者上使用这些注释时@Bean定义,如果 Bean 定义返回适当的MessageHandler(取决于注释类型),您必须设置属性(例如outputChannel,requiresReply,order等),在MessageHandler @Bean定义本身。 仅使用以下注释属性:adviceChain,autoStartup,inputChannel,phasepoller. 所有其他属性都用于处理程序。
Bean 名称是使用以下算法生成的:
  • MessageHandler (MessageSource) @Bean从方法名称中获取自己的标准名称或name属性@Bean. 这就像@Bean方法。spring-doc.cadn.net.cn

  • AbstractEndpointbean name 使用以下模式生成:[@Bean name].[decapitalizedAnnotationClassShortName]. 例如,SourcePollingChannelAdapterendpoint 的consoleSource()前面显示的定义的 bean 名称为consoleSource.inboundChannelAdapter. 与 POJO 方法不同,Bean 方法名称不包含在端点 Bean 名称中。 另请参阅端点 Bean 名称spring-doc.cadn.net.cn

  • 如果@Bean不能直接在目标端点中使用(不是MessageSource,AbstractReplyProducingMessageHandlerAbstractMessageRouter),分别AbstractStandardMessageHandlerFactoryBean已注册以委托此@Bean. 此包装器的 bean 名称是使用以下模式生成的:[@Bean name].[decapitalizedAnnotationClassShortName].[handler (or source)].spring-doc.cadn.net.cn

@Bean定义,则inputChannel必须引用声明的 bean。 如果应用程序上下文中尚不存在,则会自动声明通道。

使用 Java 配置,您可以使用任何@Conditional(例如,@Profile) 定义@Bean方法级别出于某种条件原因跳过 bean 注册。 以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@Bean
@ServiceActivator(inputChannel = "skippedChannel")
@Profile("thing")
public MessageHandler skipped() {
    return System.out::println;
}

与现有的 Spring 容器逻辑一起,消息传递端点 bean(基于@ServiceActivator注释),也未注册。spring-doc.cadn.net.cn

创建带有注释的桥梁

从 4.0 版开始,Java 配置提供了@BridgeFrom@BridgeTo @Bean要标记的方法注释MessageChannel豆子在@Configuration类。 这些确实是为了完整性而存在的,提供了一种方便的机制来声明BridgeHandler及其消息端点配置:spring-doc.cadn.net.cn

@Bean
public PollableChannel bridgeFromInput() {
    return new QueueChannel();
}

@Bean
@BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000"))
public MessageChannel bridgeFromOutput() {
    return new DirectChannel();
}
@Bean
public QueueChannel bridgeToOutput() {
    return new QueueChannel();
}

@Bean
@BridgeTo("bridgeToOutput")
public MessageChannel bridgeToInput() {
    return new DirectChannel();
}

您也可以将这些注释用作元注释。spring-doc.cadn.net.cn

为带注释的端点提供建议

消息映射规则和约定

Spring Integration实现了一种灵活的工具,通过依赖一些默认规则和定义某些约定,将消息映射到方法及其参数,而无需提供额外的配置。 以下部分中的示例阐明了规则。spring-doc.cadn.net.cn

示例方案

以下示例显示了一个未注释的参数(对象或基元),该参数不是MapProperties具有非 void 返回类型的对象:spring-doc.cadn.net.cn

public String doSomething(Object o);

输入参数是消息有效负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值被合并为返回消息的有效负载。spring-doc.cadn.net.cn

以下示例显示了一个未注释的参数(对象或基元),该参数不是MapProperties使用Message返回类型:spring-doc.cadn.net.cn

public Message doSomething(Object o);

输入参数是消息有效负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值是发送到下一个目标的新构造消息。spring-doc.cadn.net.cn

以下示例显示了一个参数,该参数是具有任意对象或原始返回类型的消息(或其子类之一):spring-doc.cadn.net.cn

public int doSomething(Message msg);

输入参数本身是Message. 返回值成为Message发送到下一个目的地。spring-doc.cadn.net.cn

以下示例显示了一个参数,该参数是Message(或其子类之一)与Message(或其子类之一)作为返回类型:spring-doc.cadn.net.cn

public Message doSomething(Message msg);

输入参数本身是Message. 返回值是新构造的Message发送到下一个目的地。spring-doc.cadn.net.cn

以下示例显示了类型为MapProperties使用Message作为返回类型:spring-doc.cadn.net.cn

public Message doSomething(Map m);

这个有点意思。 尽管乍一看,直接映射到消息头似乎很容易,但始终优先考虑Message有效载荷。 这意味着,如果Message有效负载的类型为Map,则此输入参数表示Message有效载荷。 但是,如果Message有效负载不是类型Map,转换服务不会尝试转换有效负载,并且输入参数将映射到消息头。spring-doc.cadn.net.cn

以下示例显示了两个参数,其中一个是任意类型(对象或基元),不是MapPropertiesobject 的,另一个是MapProperties类型(无论返回结果如何):spring-doc.cadn.net.cn

public Message doSomething(Map h, <T> t);

此组合包含两个输入参数,其中一个类型为Map. 非Map参数(无论顺序如何)都映射到Messagepayload 和MapProperties(无论顺序如何)都映射到消息头,为您提供了一种很好的 POJO 交互方式Message结构。spring-doc.cadn.net.cn

以下示例不显示任何参数(无论返回结果如何):spring-doc.cadn.net.cn

public String doSomething();

此消息处理程序方法是根据发送到此处理程序所连接的输入通道的消息调用的。 但是,没有Message数据被映射,从而使Message充当事件或触发器来调用处理程序。 输出根据前面描述的规则进行映射。spring-doc.cadn.net.cn

以下示例显示没有参数和 void 返回:spring-doc.cadn.net.cn

public void soSomething();

此示例与上一个示例相同,但不产生任何输出。spring-doc.cadn.net.cn

基于注释的映射

基于注释的映射是将消息映射到方法的最安全且最不模糊的方法。 以下示例演示如何将方法显式映射到标头:spring-doc.cadn.net.cn

public String doSomething(@Payload String s, @Header("someheader") String b)

正如您稍后看到的,如果没有注释,此签名将导致不明确的情况。 但是,通过将第一个参数显式映射到Messagepayload 和第二个参数的值someheadermessage header 中,我们避免了任何歧义。spring-doc.cadn.net.cn

以下示例与前面的示例几乎相同:spring-doc.cadn.net.cn

public String doSomething(@Payload String s, @RequestParam("something") String b)

@RequestMapping或任何其他非 Spring Integration 映射注释都是无关紧要的,因此被忽略,使第二个参数未映射。 尽管第二个参数可以很容易地映射到有效负载,但只能有一个有效负载。 因此,注释可以防止此方法不明确。spring-doc.cadn.net.cn

以下示例显示了另一种类似的方法,如果没有注释来澄清意图,该方法将是模棱两可的:spring-doc.cadn.net.cn

public String foo(String s, @Header("foo") String b)

唯一的区别是第一个参数隐式映射到消息有效负载。spring-doc.cadn.net.cn

以下示例显示了另一个签名,如果没有注释,它肯定会被视为不明确,因为它有两个以上的参数:spring-doc.cadn.net.cn

public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)

这个例子尤其成问题,因为它的两个参数是Map实例。 但是,使用基于注释的映射,可以轻松避免歧义。在此示例中,第一个参数映射到所有消息头,而第二个和第三个参数映射到名为“something”和“someotherthing”的消息头的值。有效负载未映射到任何参数。spring-doc.cadn.net.cn

复杂场景

以下示例使用多个参数:spring-doc.cadn.net.cn

多个参数可能会在确定适当的映射方面产生很多歧义。一般建议是使用@Payload,@Header@Headers. 本节中的示例显示了导致引发异常的不明确条件。spring-doc.cadn.net.cn

public String doSomething(String s, int i)

这两个参数的权重相等。因此,无法确定哪一个是有效载荷。spring-doc.cadn.net.cn

以下示例显示了类似的问题,仅使用三个参数:spring-doc.cadn.net.cn

public String foo(String s, Map m, String b)

尽管 Map 可以轻松映射到消息标头,但无法确定如何处理这两个 String 参数。spring-doc.cadn.net.cn

以下示例显示了另一种模棱两可的方法:spring-doc.cadn.net.cn

public String foo(Map m, Map f)

尽管有人可能会争辩说Map可以映射到消息有效负载,另一个映射到消息头,我们不能依赖顺序。spring-doc.cadn.net.cn

任何具有多个方法参数的方法签名,该参数不是 (Map,<T>)并使用未注释的参数会导致不明确的条件并触发异常。

下一组示例分别显示了多种导致歧义的方法。spring-doc.cadn.net.cn

具有多个方法的消息处理程序根据前面描述的相同规则(在示例中)进行映射。 但是,某些场景可能看起来仍然令人困惑。spring-doc.cadn.net.cn

以下示例显示了具有合法(可映射且明确)签名的多个方法:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomething(Map m);
}

(这些方法的名称相同还是名称不同没有区别)。 这Message可以映射到任一方法。 当消息有效负载可以映射到str并且消息头可以映射到m. 第二种方法也可以通过仅将消息头映射到m. 更糟糕的是,这两种方法都有相同的名称。 起初,由于以下配置,这可能看起来不明确:spring-doc.cadn.net.cn

<int:service-activator input-channel="input" output-channel="output" method="doSomething">
    <bean class="org.things.Something"/>
</int:service-activator>

它之所以有效,是因为映射首先基于有效负载,然后是其他所有内容。 换句话说,其第一个参数可以映射到有效负载的方法优先于所有其他方法。spring-doc.cadn.net.cn

现在考虑一个替代示例,它会产生一个真正模棱两可的条件:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomething(String str);
}

这两种方法都有可以映射到消息有效负载的签名。 它们也有相同的名称。 此类处理程序方法将触发异常。 但是,如果方法名称不同,则可以使用method属性(如下一个示例所示)。 以下示例显示了具有两个不同方法名称的同一示例:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomethingElse(String str);
}

以下示例演示如何使用method属性来指示映射:spring-doc.cadn.net.cn

<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse">
    <bean class="org.bar.Foo"/>
</int:service-activator>

由于配置显式映射了doSomethingElse方法,我们消除了歧义。spring-doc.cadn.net.cn