此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Integration 6.3.1Spring中文文档

此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Integration 6.3.1Spring中文文档

要创建消息通道实例,可以使用 xml 元素或 Java 配置实例,如下所示:<channel/>DirectChannelSpring中文文档

@Bean
public MessageChannel exampleChannel() {
    return new DirectChannel();
}
<int:channel id="exampleChannel"/>

当您使用没有任何子元素的元素时,它会创建一个实例 (a )。<channel/>DirectChannelSubscribableChannelSpring中文文档

要创建发布-订阅频道,请使用 元素(在 Java 中为 ),如下所示:<publish-subscribe-channel/>PublishSubscribeChannelSpring中文文档

@Bean
public MessageChannel exampleChannel() {
    return new PublishSubscribeChannel();
}
<int:publish-subscribe-channel id="exampleChannel"/>

或者,您可以提供各种子元素来创建任何可轮询的通道类型(如消息通道实现中所述)。 以下各节显示了每种通道类型的示例。<queue/>Spring中文文档

DirectChannel配置

如前所述,是默认类型。 以下列表显示了定义一个的人员:DirectChannelSpring中文文档

@Bean
public MessageChannel directChannel() {
    return new DirectChannel();
}
<int:channel id="directChannel"/>

默认通道具有轮循机制负载均衡器,并且还启用了故障转移(有关详细信息,请参阅 DirectChannel)。 要禁用其中的一个或两个,请添加一个子元素(的构造函数),并按如下方式配置属性:<dispatcher/>LoadBalancingStrategyDirectChannelSpring中文文档

@Bean
public MessageChannel failFastChannel() {
    DirectChannel channel = new DirectChannel();
    channel.setFailover(false);
    return channel;
}

@Bean
public MessageChannel failFastChannel() {
    return new DirectChannel(null);
}
<int:channel id="failFastChannel">
    <int:dispatcher failover="false"/>
</channel>

<int:channel id="channelWithFixedOrderSequenceFailover">
    <int:dispatcher load-balancer="none"/>
</int:channel>

从版本 6.3 开始,所有基于 的实现都可以配置一个而不是普通选项。 此谓词根据从当前谓词引发的异常决定是否故障转移到下一个谓词。 应使用 ErrorMessageExceptionTypeRouter 进行更复杂的错误分析。MessageChannelUnicastingDispatcherPredicate<Exception> failoverStrategyfailoverMessageHandlerSpring中文文档

数据类型通道配置

有时,使用者只能处理特定类型的有效负载,这迫使您确保输入消息的有效负载类型。 首先想到的可能是使用消息过滤器。 但是,消息过滤器所能做的就是过滤掉不符合使用者要求的消息。 另一种方法是使用基于内容的路由器,并将具有不合规数据类型的消息路由到特定的转换器,以强制转换和转换为所需的数据类型。 这将起作用,但完成相同操作的更简单方法是应用数据类型通道模式。 您可以对每个特定的有效负载数据类型使用单独的数据类型通道。Spring中文文档

若要创建仅接受包含特定有效负载类型的消息的数据类型通道,请在通道元素的属性中提供数据类型的完全限定类名,如以下示例所示:datatypeSpring中文文档

@Bean
public MessageChannel numberChannel() {
    DirectChannel channel = new DirectChannel();
    channel.setDatatypes(Number.class);
    return channel;
}
<int:channel id="numberChannel" datatype="java.lang.Number"/>

请注意,对于可分配给通道数据类型的任何类型,类型检查都会通过。 换言之,在前面的示例中,将接受有效负载为 或 . 可以以逗号分隔的列表形式提供多种类型,如以下示例所示:numberChanneljava.lang.Integerjava.lang.DoubleSpring中文文档

@Bean
public MessageChannel numberChannel() {
    DirectChannel channel = new DirectChannel();
    channel.setDatatypes(String.class, Number.class);
    return channel;
}
<int:channel id="stringOrNumberChannel" datatype="java.lang.String,java.lang.Number"/>

因此,前面示例中的“numberChannel”仅接受数据类型为 的消息。 但是,如果消息的有效负载不是必需的类型,会发生什么情况? 这取决于你是否定义了一个名为 Spring 转换服务的实例的 bean。 如果没有,那么将立即抛出一个。 但是,如果定义了 Bean,则会使用它来尝试将消息的有效负载转换为可接受的类型。java.lang.NumberintegrationConversionServiceExceptionintegrationConversionServiceSpring中文文档

您甚至可以注册自定义转换器。 例如,假设您向上面配置的“numberChannel”发送了一条带有有效负载的消息。 您可以按如下方式处理该消息:StringSpring中文文档

MessageChannel inChannel = context.getBean("numberChannel", MessageChannel.class);
inChannel.send(new GenericMessage<String>("5"));

通常,这将是一个完全合法的操作。 但是,由于我们使用数据类型通道,因此此类操作的结果将生成类似于以下内容的异常:Spring中文文档

Exception in thread "main" org.springframework.integration.MessageDeliveryException:
Channel 'numberChannel'
expected one of the following datataypes [class java.lang.Number],
but received [class java.lang.String]
…

发生异常是因为我们要求有效负载类型为 ,但我们发送了 . 因此,我们需要一些东西来将 a 转换为 . 为此,我们可以实现一个类似于以下示例的转换器:NumberStringStringNumberSpring中文文档

public static class StringToIntegerConverter implements Converter<String, Integer> {
    public Integer convert(String source) {
        return Integer.parseInt(source);
    }
}

然后,我们可以将其注册为集成转换服务的转换器,如以下示例所示:Spring中文文档

@Bean
@IntegrationConverter
public StringToIntegerConverter strToInt {
    return new StringToIntegerConverter();
}
<int:converter ref="strToInt"/>

<bean id="strToInt" class="org.springframework.integration.util.Demo.StringToIntegerConverter"/>

或者在类上标有自动扫描的注释。StringToIntegerConverter@ComponentSpring中文文档

当解析“converter”元素时,如果尚未定义 bean,它会创建 bean。 使用该转换器后,操作现在将成功,因为数据类型通道使用该转换器将有效负载转换为 .integrationConversionServicesendStringIntegerSpring中文文档

有关有效负载类型转换的更多信息,请参阅有效负载类型转换Spring中文文档

从 4.0 版开始,由 调用,该 在应用程序上下文中查找转换服务。 要使用其他转换技术,您可以在频道上指定属性。 这必须是对实现的引用。 仅使用该方法。 它为转换器提供了对消息标头的访问权限(以防转换可能需要来自标头的信息,例如 )。 该方法只能返回转换后的有效负载或完整对象。 如果是后者,转换器必须小心地从入站消息中复制所有标头。integrationConversionServiceDefaultDatatypeChannelMessageConvertermessage-converterMessageConverterfromMessagecontent-typeMessageSpring中文文档

或者,您可以声明 ID 为 的 of 类型,并且该转换器由所有具有 的通道使用。<bean/>MessageConverterdatatypeChannelMessageConverterdatatypeSpring中文文档

QueueChannel配置

要创建一个 ,请使用 sub-element。 您可以按如下方式指定通道的容量:QueueChannel<queue/>Spring中文文档

@Bean
public PollableChannel queueChannel() {
    return new QueueChannel(25);
}
<int:channel id="queueChannel">
    <queue capacity="25"/>
</int:channel>
如果未为此子元素的“capacity”属性提供值,则生成的队列是无界的。 为避免内存不足等问题,强烈建议您为有界队列设置显式值。<queue/>

持久配置QueueChannel

由于 a 提供了缓冲消息的功能,但默认情况下仅在内存中执行此操作,因此它还引入了在系统发生故障时消息丢失的可能性。 为了降低这种风险,可以通过策略接口的持久实现来支持。 有关 和 的更多详细信息,请参阅消息存储库。QueueChannelQueueChannelMessageGroupStoreMessageGroupStoreMessageStoreSpring中文文档

使用该属性时,不允许使用该属性。capacitymessage-store

当 a 收到 时,它会将消息添加到消息存储中。 当从 轮询 a 时,将从消息存储中删除它。QueueChannelMessageMessageQueueChannelSpring中文文档

默认情况下,a 将其消息存储在内存队列中,这可能会导致前面提到的消息丢失情况。 但是,Spring Integration 提供了持久性存储,例如 .QueueChannelJdbcChannelMessageStoreSpring中文文档

您可以通过添加属性来为任何消息存储配置消息存储,如以下示例所示:QueueChannelmessage-storeSpring中文文档

<int:channel id="dbBackedChannel">
    <int:queue message-store="channelStore"/>
</int:channel>

<bean id="channelStore" class="o.s.i.jdbc.store.JdbcChannelMessageStore">
    <property name="dataSource" ref="dataSource"/>
    <property name="channelMessageStoreQueryProvider" ref="queryProvider"/>
</bean>

(有关 Java/Kotlin 配置选项,请参阅下面的示例。Spring中文文档

Spring Integration JDBC 模块还为许多流行的数据库提供了模式数据定义语言 (DDL)。 这些模式位于该模块()的org.springframework.integration.jdbc.store.channel包中。spring-integration-jdbcSpring中文文档

一个重要的功能是,对于任何事务持久性存储(如 ),只要轮询器配置了事务,仅当事务成功完成时,才能永久删除从存储中删除的消息。 否则,事务将回滚,并且不会丢失。JdbcChannelMessageStoreMessage

随着越来越多的与“NoSQL”数据存储相关的 Spring 项目开始为这些存储提供底层支持,消息存储库的许多其他实现也可用。 如果找不到满足特定需求的接口,也可以提供自己的接口实现。MessageGroupStoreSpring中文文档

从版本 4.0 开始,我们建议将实例配置为尽可能使用 。 与一般消息存储库相比,这些通常针对此用途进行了优化。 如果为 ,则在 FIFO 中按优先级顺序接收消息。 优先级的概念由消息存储实现决定。 例如,以下示例显示了 MongoDB 通道消息存储库的 Java 配置:QueueChannelChannelMessageStoreChannelMessageStoreChannelPriorityMessageStoreSpring中文文档

@Bean
public BasicMessageGroupStore mongoDbChannelMessageStore(MongoDbFactory mongoDbFactory) {
    MongoDbChannelMessageStore store = new MongoDbChannelMessageStore(mongoDbFactory);
    store.setPriorityEnabled(true);
    return store;
}

@Bean
public PollableChannel priorityQueue(BasicMessageGroupStore mongoDbChannelMessageStore) {
    return new PriorityChannel(new MessageGroupQueue(mongoDbChannelMessageStore, "priorityQueue"));
}
@Bean
public IntegrationFlow priorityFlow(PriorityCapableChannelMessageStore mongoDbChannelMessageStore) {
    return IntegrationFlow.from((Channels c) ->
            c.priority("priorityChannel", mongoDbChannelMessageStore, "priorityGroup"))
            ....
            .get();
}
@Bean
fun priorityFlow(mongoDbChannelMessageStore: PriorityCapableChannelMessageStore) =
    integrationFlow {
        channel { priority("priorityChannel", mongoDbChannelMessageStore, "priorityGroup") }
    }
注意上课。 这是使用操作的实现。MessageGroupQueueBlockingQueueMessageGroupStore

自定义环境的另一个选项是由子元素的属性或其特定构造函数提供的。 此属性提供对任何实现的引用。 例如,可以按如下方式配置 Hazelcast 分布式 IQueueQueueChannelref<int:queue>java.util.QueueSpring中文文档

@Bean
public HazelcastInstance hazelcastInstance() {
    return Hazelcast.newHazelcastInstance(new Config()
                                           .setProperty("hazelcast.logging.type", "log4j"));
}

@Bean
public PollableChannel distributedQueue() {
    return new QueueChannel(hazelcastInstance()
                              .getQueue("springIntegrationQueue"));
}
如果未为此子元素的“capacity”属性提供值,则生成的队列是无界的。 为避免内存不足等问题,强烈建议您为有界队列设置显式值。<queue/>
使用该属性时,不允许使用该属性。capacitymessage-store
一个重要的功能是,对于任何事务持久性存储(如 ),只要轮询器配置了事务,仅当事务成功完成时,才能永久删除从存储中删除的消息。 否则,事务将回滚,并且不会丢失。JdbcChannelMessageStoreMessage
注意上课。 这是使用操作的实现。MessageGroupQueueBlockingQueueMessageGroupStore

PublishSubscribeChannel配置

要创建 ,请使用 <publish-subscribe-channel/> 元素。 使用此元素时,还可以指定用于发布消息的元素(如果未指定,则在发件人的线程中发布),如下所示:PublishSubscribeChanneltask-executorSpring中文文档

@Bean
public MessageChannel pubsubChannel() {
    return new PublishSubscribeChannel(someExecutor());
}
<int:publish-subscribe-channel id="pubsubChannel" task-executor="someExecutor"/>

如果提供 下游的重排序器或聚合器,则可以将通道上的“apply-sequence”属性设置为 。 这样做表示通道应在传递消息之前设置 和 消息标头以及相关 ID。 例如,如果有 5 个订阅者,则 将设置为 ,并且消息的标头值范围为 。PublishSubscribeChanneltruesequence-sizesequence-numbersequence-size5sequence-number15Spring中文文档

除了 ,您还可以配置 . 默认情况下,使用实现将错误发送到标头或全局实例。 如果未配置 an,则忽略 ,并将异常直接抛出到调用方的线程。ExecutorErrorHandlerPublishSubscribeChannelMessagePublishingErrorHandlerMessageChannelerrorChannelerrorChannelExecutorErrorHandlerSpring中文文档

如果提供 的 或 的下游,则可以将通道上的“apply-sequence”属性设置为 。 这样做表明通道应在传递消息之前设置序列大小和序列号消息标头以及相关 ID。 例如,如果有 5 个订阅者,则 sequence-size 将设置为 ,并且消息的序列号标头值范围为 。ResequencerAggregatorPublishSubscribeChanneltrue515Spring中文文档

下面的示例演示如何将标头设置为:apply-sequencetrueSpring中文文档

@Bean
public MessageChannel pubsubChannel() {
    PublishSubscribeChannel channel = new PublishSubscribeChannel();
    channel.setApplySequence(true);
    return channel;
}
<int:publish-subscribe-channel id="pubsubChannel" apply-sequence="true"/>
默认情况下,该值为发布-订阅通道,以便发布-订阅通道可以将完全相同的消息实例发送到多个出站通道。 由于 Spring Integration 强制执行有效负载和标头引用的不可变性,因此当标志设置为 时,通道将创建具有相同有效负载引用但不同标头值的新实例。apply-sequencefalsetrueMessage

从版本 5.4.3 开始,还可以使用 its 选项进行配置,以指示此频道在没有订阅者时不会静默忽略消息。 当没有订阅者时,将抛出带有消息的 A,并且此选项设置为 。PublishSubscribeChannelrequireSubscribersBroadcastingDispatcherMessageDispatchingExceptionDispatcher has no subscriberstrueSpring中文文档

默认情况下,该值为发布-订阅通道,以便发布-订阅通道可以将完全相同的消息实例发送到多个出站通道。 由于 Spring Integration 强制执行有效负载和标头引用的不可变性,因此当标志设置为 时,通道将创建具有相同有效负载引用但不同标头值的新实例。apply-sequencefalsetrueMessage

ExecutorChannel

要创建一个 ,请添加带有属性的子元素。 属性的值可以引用上下文中的任何属性。 例如,这样做可以配置线程池,以便将消息分派给订阅的处理程序。 如前所述,这样做会破坏发送方和接收方之间的单线程执行上下文,以便处理程序的调用不会共享任何活动事务上下文(即,处理程序可能会抛出 ,但调用已成功返回)。 下面的示例演示如何使用该元素并在属性中指定执行程序:ExecutorChannel<dispatcher>task-executorTaskExecutorExceptionsenddispatchertask-executorSpring中文文档

@Bean
public MessageChannel executorChannel() {
    return new ExecutorChannel(someExecutor());
}
<int:channel id="executorChannel">
    <int:dispatcher task-executor="someExecutor"/>
</int:channel>

和 选项在 <dispatcher/> 子元素上也可用,如前面的 DirectChannel 配置中所述。 同样的默认值也适用。 因此,通道具有启用故障转移的循环负载均衡策略,除非为其中一个或两个属性提供显式配置,如以下示例所示:load-balancerfailoverSpring中文文档

<int:channel id="executorChannelWithoutFailover">
    <int:dispatcher task-executor="someExecutor" failover="false"/>
</int:channel>

和 选项在 <dispatcher/> 子元素上也可用,如前面的 DirectChannel 配置中所述。 同样的默认值也适用。 因此,通道具有启用故障转移的循环负载均衡策略,除非为其中一个或两个属性提供显式配置,如以下示例所示:load-balancerfailoverSpring中文文档

<int:channel id="executorChannelWithoutFailover">
    <int:dispatcher task-executor="someExecutor" failover="false"/>
</int:channel>

PriorityChannel配置

要创建一个 ,请使用 sub-element,如以下示例所示:PriorityChannel<priority-queue/>Spring中文文档

@Bean
public PollableChannel priorityChannel() {
    return new PriorityChannel(20);
}
<int:channel id="priorityChannel">
    <int:priority-queue capacity="20"/>
</int:channel>

默认情况下,通道会查阅消息的标头。 但是,您可以改为提供自定义引用。 另请注意,(与其他类型一样)确实支持该属性。 与 一样,它也支持一个属性。 以下示例演示了所有这些:priorityComparatorPriorityChanneldatatypeQueueChannelcapacitySpring中文文档

@Bean
public PollableChannel priorityChannel() {
    PriorityChannel channel = new PriorityChannel(20, widgetComparator());
    channel.setDatatypes(example.Widget.class);
    return channel;
}
<int:channel id="priorityChannel" datatype="example.Widget">
    <int:priority-queue comparator="widgetComparator"
                    capacity="10"/>
</int:channel>

从版本 4.0 开始,子元素支持该选项(在这种情况下不允许)。 消息存储库必须是 . 的实现目前为 、 和 提供。 有关详细信息,请参阅 QueueChannel 配置消息存储。 您可以在后备消息通道中找到示例配置。priority-channelmessage-storecomparatorcapacityPriorityCapableChannelMessageStorePriorityCapableChannelMessageStoreRedisJDBCMongoDBSpring中文文档

RendezvousChannel配置

当队列子元素为 时,将创建 A。 它不为前面描述的配置选项提供任何其他配置选项,并且其队列不接受任何容量值,因为它是零容量直接切换队列。 下面的示例演示如何声明:RendezvousChannel<rendezvous-queue>RendezvousChannelSpring中文文档

@Bean
public PollableChannel rendezvousChannel() {
    return new RendezvousChannel();
}
<int:channel id="rendezvousChannel"/>
    <int:rendezvous-queue/>
</int:channel>

作用域通道配置

任何通道都可以配置属性,如以下示例所示:scopeSpring中文文档

<int:channel id="threadLocalChannel" scope="thread"/>

信道拦截器配置

消息通道也可能具有侦听器,如通道侦听器中所述。 子元素可以添加到(或更具体的元素类型)中。 您可以提供属性来引用实现接口的任何 Spring 托管对象,如以下示例所示:<interceptors/><channel/>refChannelInterceptorSpring中文文档

<int:channel id="exampleChannel">
    <int:interceptors>
        <ref bean="trafficMonitoringInterceptor"/>
    </int:interceptors>
</int:channel>

通常,我们建议在单独的位置定义拦截器实现,因为它们通常提供可以跨多个通道重用的通用行为。Spring中文文档

全局信道拦截器配置

信道拦截器提供了一种简洁明了的方式来应用每个信道的横切行为。 如果应在多个信道上应用相同的行为,则为每个信道配置同一组拦截器并不是最有效的方法。 为了避免重复配置,同时使拦截器能够应用于多个通道,Spring Integration 提供了全局拦截器。 请看以下一对示例:Spring中文文档

<int:channel-interceptor pattern="input*, thing2*, thing1, !cat*" order="3">
    <bean class="thing1.thing2SampleInterceptor"/>
</int:channel-interceptor>
<int:channel-interceptor ref="myInterceptor" pattern="input*, thing2*, thing1, !cat*" order="3"/>

<bean id="myInterceptor" class="thing1.thing2SampleInterceptor"/>

每个元素都允许您定义一个全局拦截器,该拦截器应用于与该属性定义的任何模式匹配的所有通道。 在前一种情况下,全局拦截器应用于“thing1”通道和所有其他以“thing2”或“input”开头的通道,但不应用于以“thing3”开头的通道(从5.0版开始)。<channel-interceptor/>patternSpring中文文档

将此语法添加到模式中会导致一个可能的(尽管可能不太可能)问题。 如果您有一个命名的 bean,并且您在信道拦截器的模式中包含了 的模式,则它不再匹配。 该模式现在匹配所有未命名的 Bean 。 在这种情况下,您可以使用 . 该模式与名为 的 Bean 匹配。!thing1!thing1patternthing1!\\!thing1!thing1

order 属性允许您管理当给定信道上有多个拦截器时,此拦截器的注入位置。 例如,通道“inputChannel”可以在本地配置单独的侦听器(见下文),如以下示例所示:Spring中文文档

<int:channel id="inputChannel">
  <int:interceptors>
    <int:wire-tap channel="logger"/>
  </int:interceptors>
</int:channel>

一个合理的问题是“如何注入全局拦截器,以配合本地配置的其他拦截器或通过其他全局拦截器定义配置? 当前的实现提供了一种简单的机制来定义拦截器的执行顺序。 属性中的正数确保在任何现有拦截器之后注入拦截器,而负数确保拦截器在现有拦截器之前注入。 这意味着,在前面的示例中,全局拦截器是在本地配置的“窃听”拦截器之后注入的(因为它大于)。 如果有另一个全局拦截器具有匹配,则通过比较两个拦截器属性的值来确定其顺序。 若要在现有拦截器之前注入全局拦截器,请对属性使用负值。orderorder0patternorderorderSpring中文文档

请注意,和 属性都是可选的。 的默认值为 0,默认值为 “*”(以匹配所有通道)。orderpatternorderpattern
将此语法添加到模式中会导致一个可能的(尽管可能不太可能)问题。 如果您有一个命名的 bean,并且您在信道拦截器的模式中包含了 的模式,则它不再匹配。 该模式现在匹配所有未命名的 Bean 。 在这种情况下,您可以使用 . 该模式与名为 的 Bean 匹配。!thing1!thing1patternthing1!\\!thing1!thing1
请注意,和 属性都是可选的。 的默认值为 0,默认值为 “*”(以匹配所有通道)。orderpatternorderpattern

丝锥

如前所述,Spring Integration 提供了一个简单的窃听拦截器。 您可以在元素内的任何通道上配置分接器。 这样做对于调试特别有用,可以与 Spring Integration 的日志记录通道适配器结合使用,如下所示:<interceptors/>Spring中文文档

<int:channel id="in">
    <int:interceptors>
        <int:wire-tap channel="logger"/>
    </int:interceptors>
</int:channel>

<int:logging-channel-adapter id="logger" level="DEBUG"/>
'logging-channel-adapter' 还接受 'expression' 属性,以便您可以根据 'payload' 和 'headers' 变量评估 SpEL 表达式。 或者,若要记录完整的消息结果,请为 'log-full-message' 属性提供值。 默认情况下,它只记录有效负载。 将其设置为启用除有效负载之外的所有标头的日志记录。 “expression”选项提供了最大的灵活性(例如,)。toString()truefalsetrueexpression="payload.user.name"

关于窃听器和其他类似组件(消息发布配置)的一个常见误解是,它们本质上是自动异步的。 默认情况下,不会异步调用作为组件的接线分流器。 相反,Spring Integration 专注于配置异步行为的单一统一方法:消息通道。 使消息流的某些部分同步或异步的是在该流中配置的消息通道的类型。 这是消息通道抽象的主要好处之一。 从框架诞生之初,我们就一直强调消息通道作为框架一等公民的必要性和价值。 它不仅仅是 EIP 模式的内部隐式实现。 它作为可配置组件完全公开给最终用户。 因此,窃听器组件仅负责执行以下任务:Spring中文文档

它本质上是桥接模式的变体,但它封装在通道定义中(因此更容易启用和禁用而不会中断流)。 此外,与网桥不同的是,它基本上是另一个消息流的分支。 该流是同步的还是异步的?答案取决于“channelB”是消息通道的类型。 我们有以下选项:直接通道、可轮询通道和执行程序通道。 最后两个打破了线程边界,使通过此类通道进行通信是异步的,因为将消息从该通道调度到其订阅的处理程序发生在与用于将消息发送到该通道的线程不同的线程上。 这就是使您的窃听流同步或异步的原因。 它与框架中的其他组件(如消息发布者)一致,并且通过让您不必提前担心(除了编写线程安全代码)来增加一致性和简单性,即特定代码段是应实现为同步还是异步。 两条代码(例如,组件 A 和组件 B)在消息通道上的实际连接是使它们的协作同步或异步的原因。 您甚至可能希望在将来从同步更改为异步,而消息通道可让您在不接触代码的情况下快速完成。Spring中文文档

关于窃听的最后一点是,尽管上面提供了默认情况下不是异步的基本原理,但您应该记住,通常希望尽快传递消息。 因此,使用异步通道选项作为接线器的出站通道是很常见的。 但是,默认情况下不强制执行异步行为。 如果我们这样做,有许多用例会中断,包括您可能不想中断事务边界。 也许您使用窃听模式进行审核,并且您确实希望在原始事务中发送审核消息。 例如,您可以将分路器连接到 JMS 出站通道适配器。 这样一来,你就可以两全其美:1)JMS消息的发送可以在事务中发生,而2)它仍然是一个“即发即弃”的操作,从而防止了主消息流中任何明显的延迟。Spring中文文档

从版本 4.0 开始,当侦听器(如 WireTap)引用通道时,请务必避免循环引用。 您需要将此类信道排除在当前拦截器截获的信道之外。 这可以通过适当的模式或编程方式完成。 如果您有引用 的自定义,请考虑实现 。 这样,框架就会根据提供的模式询问拦截器是否可以拦截每个候选通道。 还可以在侦听器方法中添加运行时保护,以确保通道不是侦听器引用的通道。 使用这两种技术。ChannelInterceptorchannelVetoCapableInterceptorWireTap

从版本 4.3 开始,具有采用实例而不是实例的其他构造函数。 这对于 Java 配置和使用通道自动创建逻辑时非常方便。 目标 Bean 从稍后提供的 bean 中解析出来,在与 拦截 器。WireTapchannelNameMessageChannelMessageChannelchannelNameSpring中文文档

通道解析需要 ,因此接线器实例必须是 Spring 管理的 bean。BeanFactory

这种后期绑定方法还允许使用 Java DSL 配置简化典型的窃听模式,如以下示例所示:Spring中文文档

@Bean
public PollableChannel myChannel() {
    return MessageChannels.queue()
            .wireTap("loggingFlow.input")
            .get();
}

@Bean
public IntegrationFlow loggingFlow() {
    return f -> f.log();
}
'logging-channel-adapter' 还接受 'expression' 属性,以便您可以根据 'payload' 和 'headers' 变量评估 SpEL 表达式。 或者,若要记录完整的消息结果,请为 'log-full-message' 属性提供值。 默认情况下,它只记录有效负载。 将其设置为启用除有效负载之外的所有标头的日志记录。 “expression”选项提供了最大的灵活性(例如,)。toString()truefalsetrueexpression="payload.user.name"
从版本 4.0 开始,当侦听器(如 WireTap)引用通道时,请务必避免循环引用。 您需要将此类信道排除在当前拦截器截获的信道之外。 这可以通过适当的模式或编程方式完成。 如果您有引用 的自定义,请考虑实现 。 这样,框架就会根据提供的模式询问拦截器是否可以拦截每个候选通道。 还可以在侦听器方法中添加运行时保护,以确保通道不是侦听器引用的通道。 使用这两种技术。ChannelInterceptorchannelVetoCapableInterceptorWireTap
通道解析需要 ,因此接线器实例必须是 Spring 管理的 bean。BeanFactory

条件分接器

窃听器可以通过使用 or 属性成为条件。 它们引用一个 bean,该 bean 可以在运行时确定消息是否应转到分流通道。 类似地,这是一个布尔 SpEL 表达式,它执行相同的目的:如果表达式的计算结果为 ,则消息将发送到分路通道。selectorselector-expressionselectorMessageSelectorselector-expressiontrueSpring中文文档

全局分接器配置

可以将全局窃听器配置为全局信道拦截器配置的特例。 为此,请配置顶级元素。 现在,除了常规的命名空间支持之外,还支持 和 属性,其工作方式与 . 以下示例演示如何配置全局窃听器:wire-tapwire-tappatternorderchannel-interceptorSpring中文文档

@Bean
@GlobalChannelInterceptor(patterns = "input*,thing2*,thing1", order = 3)
public WireTap wireTap(MessageChannel wiretapChannel) {
    return new WireTap(wiretapChannel);
}
<int:wire-tap pattern="input*, thing2*, thing1" order="3" channel="wiretapChannel"/>
全局分接器提供了一种在外部配置单通道分接器的便捷方法,而无需修改现有通道配置。 为此,请将该属性设置为目标频道名称。 例如,您可以使用此技术配置测试用例以验证通道上的消息。pattern
全局分接器提供了一种在外部配置单通道分接器的便捷方法,而无需修改现有通道配置。 为此,请将该属性设置为目标频道名称。 例如,您可以使用此技术配置测试用例以验证通道上的消息。pattern