>(m ->
+ "thing3".equals(m.getPayload())),
+ f -> f.channel(c -> c.queue("recipientListSubFlow3Result")))
+ .defaultOutputToParentFlow())
+ .get();
+}
+```
+
+`.routeToRecipients()`定义的`.defaultOutputToParentFlow()`允许你将路由器的`defaultOutput`设置为网关,以继续处理主流中不匹配的消息。
+
+另请参见[lambdas 和`Message>`参数]。
+
+### [](#java-dsl-splitters)分离器
+
+要创建拆分器,请使用`split()`EIP 方法。默认情况下,如果有效负载是`Iterable`、`Iterator`、`Array`、`Stream`或活性`Publisher`,则`split()`方法将每个项输出为单独的消息。它接受 lambda、spel 表达式或任何`AbstractMessageSplitter`实现。或者,你可以使用它而不需要参数来提供`DefaultMessageSplitter`。下面的示例展示了如何通过提供 lambda 来使用`split()`方法:
+
+```
+@Bean
+public IntegrationFlow splitFlow() {
+ return IntegrationFlows.from("splitInput")
+ .split(s -> s.applySequence(false).delimiters(","))
+ .channel(MessageChannels.executor(taskExecutor()))
+ .get();
+}
+```
+
+前面的示例创建了一个拆分器,该拆分包含以逗号分隔的`String`的消息。
+
+另请参见[lambdas 和`Message>`参数]。
+
+### [](#java-dsl-aggregators)聚合器和重排序程序
+
+`Aggregator`在概念上与`Splitter`相反。它将单个消息的序列聚合到单个消息中,并且必然更复杂。默认情况下,聚合器返回一条包含来自传入消息的有效负载集合的消息。同样的规则也适用于`Resequencer`。下面的示例展示了拆分器-聚合器模式的典型示例:
+
+```
+@Bean
+public IntegrationFlow splitAggregateFlow() {
+ return IntegrationFlows.from("splitAggregateInput")
+ .split()
+ .channel(MessageChannels.executor(this.taskExecutor()))
+ .resequence()
+ .aggregate()
+ .get();
+}
+```
+
+`split()`方法将列表分割为单个消息,并将它们发送到`ExecutorChannel`。`resequence()`方法根据消息标题中的序列详细信息对消息进行重新排序。`aggregate()`方法收集这些消息。
+
+但是,你可以通过指定发布策略和相关策略等来更改默认行为。考虑以下示例:
+
+```
+.aggregate(a ->
+ a.correlationStrategy(m -> m.getHeaders().get("myCorrelationKey"))
+ .releaseStrategy(g -> g.size() > 10)
+ .messageStore(messageStore()))
+```
+
+前面的示例将具有`myCorrelationKey`头的消息关联起来,并在至少积累了 10 个头的情况下释放这些消息。
+
+对于`resequence()`EIP 方法,提供了类似的 lambda 配置。
+
+### [](#java-dsl-handle)服务激活器和`.handle()`方法
+
+`.handle()`EIP 方法的目标是在某些 POJO 上调用任何`MessageHandler`实现或任何方法。另一种选择是使用 lambda 表达式来定义“活动”。因此,我们引入了一个通用的`GenericHandler`功能接口。它的`handle`方法需要两个参数:`P payload`和`MessageHeaders headers`(从版本 5.1 开始)。有了这一点,我们可以将流定义如下:
+
+```
+@Bean
+public IntegrationFlow myFlow() {
+ return IntegrationFlows.from("flow3Input")
+ .handle((p, h) -> p * 2)
+ .get();
+}
+```
+
+前面的示例将它接收到的任何整数加倍。
+
+然而, Spring 集成的一个主要目标是`loose coupling`,通过从消息有效负载到消息处理程序的目标参数的运行时类型转换。由于 Java 不支持 lambda 类的泛型类型解析,因此我们引入了一个解决方案,为大多数 EIP 方法和`LambdaMessageProcessor`提供了一个额外的`payloadType`参数。这样就将困难的转换工作委托给 Spring 的`ConversionService`,它使用提供的`type`和请求的消息来实现目标方法参数。下面的示例显示了结果`IntegrationFlow`可能是什么样子的:
+
+```
+@Bean
+public IntegrationFlow integerFlow() {
+ return IntegrationFlows.from("input")
+ .transform(p - > new String(p, "UTF-8"))
+ .handle(Integer.class, (p, h) -> p * 2)
+ .get();
+}
+```
+
+我们还可以在`ConversionService`中注册一些`BytesToIntegerConverter`,以消除附加的`.transform()`:
+
+```
+@Bean
+@IntegrationConverter
+public BytesToIntegerConverter bytesToIntegerConverter() {
+ return new BytesToIntegerConverter();
+}
+
+@Bean
+public IntegrationFlow integerFlow() {
+ return IntegrationFlows.from("input")
+ .handle(Integer.class, (p, h) -> p * 2)
+ .get();
+}
+```
+
+另请参见[lambdas 和`Message>`参数]。
+
+### [](#java-dsl-gateway)运营商网关()
+
+在`IntegrationFlow`定义中的`gateway()`运算符是一种特殊的服务激活器实现,通过其输入通道调用一些其他端点或集成流并等待应答。从技术上讲,它在``定义中扮演与嵌套``组件相同的角色(参见[从一条链子中调用一条链子](./chain.html#chain-gateway)),并允许流更干净、更直接。从逻辑上和业务角度来看,它是一个消息传递网关,允许在目标集成解决方案的不同部分之间分配和重用功能(参见[消息传递网关](./gateway.html#gateway))。对于不同的目标,这个操作符有几个重载:
+
+* `gateway(String requestChannel)`按其名称向某个端点的输入通道发送消息;
+
+* `gateway(MessageChannel requestChannel)`通过直接注入向某个端点的输入通道发送消息;
+
+* `gateway(IntegrationFlow flow)`向所提供的输入通道发送消息`IntegrationFlow`。
+
+所有这些都具有一个具有第二个`Consumer`参数的变体,以配置目标`GatewayMessageHandler`和相应的`AbstractEndpoint`。此外,基于`IntegrationFlow`的方法还允许调用现有的`IntegrationFlow` Bean 或通过用于`IntegrationFlow`功能接口的就地 lambda 将流声明为子流,或者在`private`方法中将其提取为更干净的代码样式:
+
+```
+@Bean
+IntegrationFlow someFlow() {
+ return IntegrationFlows
+ .from(...)
+ .gateway(subFlow())
+ .handle(...)
+ .get();
+}
+
+private static IntegrationFlow subFlow() {
+ return f -> f
+ .scatterGather(s -> s.recipientFlow(...),
+ g -> g.outputProcessor(MessageGroup::getOne))
+}
+```
+
+| |如果下游流并不总是返回一个响应,你应该将`requestTimeout`设置为 0,以防止无限期地挂起调用线程。
在这种情况下,流将在该点结束,线程将被释放以进行进一步的工作。|
+|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+### [](#java-dsl-log)运算符日志()
+
+为了方便起见,为了记录通过 Spring 集成流(``)的消息行程,呈现了一个`log()`操作符。在内部,它由`WireTap``ChannelInterceptor`表示,其订阅服务器为`LoggingHandler`。它负责将传入消息记录到下一个端点或当前通道中。下面的示例展示了如何使用`LoggingHandler`:
+
+```
+.filter(...)
+.log(LoggingHandler.Level.ERROR, "test.category", m -> m.getHeaders().getId())
+.route(...)
+```
+
+在前面的示例中,`id`头在`ERROR`级别记录到`test.category`中,仅用于传递过滤器和路由之前的消息。
+
+当这个操作符在流程的末尾使用时,它是单向处理程序,流程结束。要使其成为一个产生回复的流,你可以在`log()`之后使用一个简单的`bridge()`,或者,从版本 5.1 开始,你可以使用一个`logAndReply()`操作符。`logAndReply`只能在流的末尾使用。
+
+### [](#java-dsl-intercept)操作符截获()
+
+从版本 5.3 开始,`intercept()`操作符允许在流程中的当前`ChannelInterceptor`处注册一个或多个`ChannelInterceptor`实例。这是通过`MessageChannels`API 创建显式`MessageChannel`API 的一种替代方法。下面的示例使用`MessageSelectingInterceptor`来拒绝某些异常消息:
+
+```
+.transform(...)
+.intercept(new MessageSelectingInterceptor(m -> m.getPayload().isValid()))
+.handle(...)
+```
+
+### [](#java-dsl-wiretap)`MessageChannelSpec.wireTap()`
+
+Spring 集成包括`.wireTap()`Fluent API`MessageChannelSpec`Builders。下面的示例展示了如何使用`wireTap`方法记录输入:
+
+```
+@Bean
+public QueueChannelSpec myChannel() {
+ return MessageChannels.queue()
+ .wireTap("loggingFlow.input");
+}
+
+@Bean
+public IntegrationFlow loggingFlow() {
+ return f -> f.log();
+}
+```
+
+| |如果`MessageChannel`是`InterceptableChannel`的实例,则将`log()`、`wireTap()`或`intercept()`运算符应用于当前的`MessageChannel`。
否则,将向当前配置的端点的流中注入一个中间件`DirectChannel`。在下面的示例中,将`WireTap`拦截器直接添加到`myChannel`中,因为`DirectChannel`实现了`InterceptableChannel`:
```
@Bean
MessageChannel myChannel() {
return new DirectChannel();
}
...
.channel(myChannel())
.log()
}
```|
+|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+当当前的`MessageChannel`不实现`InterceptableChannel`时,一个隐式的`DirectChannel`和`BridgeHandler`被注入到`IntegrationFlow`中,并且`WireTap`被添加到这个新的`DirectChannel`中。以下示例没有任何通道声明:
+
+```
+.handle(...)
+.log()
+}
+```
+
+在前面的示例中(并且在没有信道被声明的任何时间),隐式的`DirectChannel`被注入在`IntegrationFlow`的当前位置中,并用作当前配置的`ServiceActivatingHandler`的输出信道(来自`.handle()`,[前面描述的](#java-dsl-handle))。
+
+### [](#java-dsl-flows)处理消息流
+
+`IntegrationFlowBuilder`提供了一个顶级 API 来生成连接到消息流的集成组件。当你的集成可以用单个流(通常是这种情况)来完成时,这是很方便的。交替地`IntegrationFlow`实例可以通过`MessageChannel`实例进行连接。
+
+默认情况下,`MessageFlow`在 Spring 集成术语中表现为“链”。也就是说,端点由`DirectChannel`实例自动隐式连接。消息流实际上并不是作为一个链构建的,这提供了更多的灵活性。例如,如果你知道它的`inputChannel`名称(也就是说,如果你显式地定义了它),那么你可以向流中的任何组件发送消息。你还可以在流中引用外部定义的通道,以允许使用通道适配器(以启用远程传输协议、文件 I/O 等),而不是直接通道。因此,DSL 不支持 Spring Integration`chain`元素,因为在这种情况下它不会增加太多的值。
+
+由于 Spring 集成 Java DSL 产生了与任何其他配置选项相同的 Bean 定义模型,并且是基于现有的 Spring 框架`@Configuration`基础设施的,因此可以与 XML 定义一起使用并有线 Spring 集成消息注释配置。
+
+你还可以使用 lambda 定义直接`IntegrationFlow`实例。下面的示例展示了如何做到这一点:
+
+```
+@Bean
+public IntegrationFlow lambdaFlow() {
+ return f -> f.filter("World"::equals)
+ .transform("Hello "::concat)
+ .handle(System.out::println);
+}
+```
+
+这个定义的结果是使用隐式直接通道连接的同一组集成组件。这里的唯一限制是,这个流是从一个命名的直接通道开始的-`lambdaFlow.input`。此外,lambda 流不能从`MessageSource`或`MessageProducer`开始。
+
+从版本 5.1 开始,这种`IntegrationFlow`被包装到代理,以公开生命周期控制,并提供对内部关联`inputChannel`的`inputChannel`的访问。
+
+从版本 5.0.6 开始,在`IntegrationFlow`中为组件生成的 Bean 名称包括流 Bean,后面跟着一个点(`.`)作为前缀。例如,前面示例中的`ConsumerEndpointFactoryBean`的`.transform("Hello "::concat)`的结果是 Bean 名称`lambdaFlow.o.s.i.config.ConsumerEndpointFactoryBean#0`。(`o.s.i`是从`org.springframework.integration`到适合页面的缩写。)该端点的`Transformer`实现 Bean 的 Bean 名称为`lambdaFlow.transformer#0`(从版本 5.1 开始),其中使用的是其组件类型,而不是`MethodInvokingTransformer`类的完全限定名称。当必须在流中生成 Bean 名称时,对所有`NamedComponent`s 应用相同的模式。 Bean 这些生成的名称与流 ID 一起前置,以用于诸如解析日志或在某些分析工具中将组件分组在一起的目的,以及在运行时并发注册集成流时避免竞争条件。有关更多信息,请参见[动态和运行时集成流](#java-dsl-runtime-flows)。
+
+### [](#java-dsl-function-expression)`FunctionExpression`
+
+我们引入了`FunctionExpression`类(spel 的`Expression`接口的一种实现)来让我们使用 lambdas 和`generics`。当存在来自核心 Spring 集成的隐式`Strategy`变量时,将为 DSL 组件提供`Function`选项以及`expression`选项。下面的示例展示了如何使用函数表达式:
+
+```
+.enrich(e -> e.requestChannel("enrichChannel")
+ .requestPayload(Message::getPayload)
+ .propertyFunction("date", m -> new Date()))
+```
+
+`FunctionExpression`还支持运行时类型转换,就像`SpelExpression`中所做的那样。
+
+### [](#java-dsl-subflows)子流支持
+
+一些`if…else`和`publish-subscribe`组件提供了通过使用子流指定其逻辑或映射的能力。最简单的示例是`.publishSubscribeChannel()`,如下例所示:
+
+```
+@Bean
+public IntegrationFlow subscribersFlow() {
+ return flow -> flow
+ .publishSubscribeChannel(Executors.newCachedThreadPool(), s -> s
+ .subscribe(f -> f
+ .handle((p, h) -> p / 2)
+ .channel(c -> c.queue("subscriber1Results")))
+ .subscribe(f -> f
+ .handle((p, h) -> p * 2)
+ .channel(c -> c.queue("subscriber2Results"))))
+ .handle((p, h) -> p * 3)
+ .channel(c -> c.queue("subscriber3Results"));
+}
+```
+
+你可以使用单独的`IntegrationFlow``@Bean`定义来实现相同的结果,但是我们希望你发现逻辑组合的子流样式是有用的。我们发现,这会导致代码更短(因此也更可读)。
+
+从版本 5.3 开始,提供了一个基于`BroadcastCapableChannel`的`publishSubscribeChannel()`实现,以在代理支持的消息通道上配置子流订阅服务器。例如,我们现在可以将几个订阅服务器配置为`Jms.publishSubscribeChannel()`上的子流:
+
+```
+@Bean
+public BroadcastCapableChannel jmsPublishSubscribeChannel() {
+ return Jms.publishSubscribeChannel(jmsConnectionFactory())
+ .destination("pubsub")
+ .get();
+}
+
+@Bean
+public IntegrationFlow pubSubFlow() {
+ return f -> f
+ .publishSubscribeChannel(jmsPublishSubscribeChannel(),
+ pubsub -> pubsub
+ .subscribe(subFlow -> subFlow
+ .channel(c -> c.queue("jmsPubSubBridgeChannel1")))
+ .subscribe(subFlow -> subFlow
+ .channel(c -> c.queue("jmsPubSubBridgeChannel2"))));
+}
+
+@Bean
+public BroadcastCapableChannel jmsPublishSubscribeChannel(ConnectionFactory jmsConnectionFactory) {
+ return (BroadcastCapableChannel) Jms.publishSubscribeChannel(jmsConnectionFactory)
+ .destination("pubsub")
+ .get();
+}
+```
+
+类似的`publish-subscribe`子流组合提供了`.routeToRecipients()`方法。
+
+另一个例子是在`.filter()`方法上使用`.discardFlow()`而不是`.discardChannel()`。
+
+`.route()`值得特别关注。考虑以下示例:
+
+```
+@Bean
+public IntegrationFlow routeFlow() {
+ return f -> f
+ .route(p -> p % 2 == 0,
+ m -> m.channelMapping("true", "evenChannel")
+ .subFlowMapping("false", sf ->
+ sf.handle((p, h) -> p * 3)))
+ .transform(Object::toString)
+ .channel(c -> c.queue("oddChannel"));
+}
+```
+
+`.channelMapping()`继续工作,就像在常规`Router`映射中一样,但是`.subFlowMapping()`将该子流绑定到主流。换句话说,任何路由器的子流在`.route()`之后返回到主流。
+
+| |有时,你需要从`.subFlowMapping()`中引用一个已存在的`IntegrationFlow``@Bean`。
下面的示例展示了如何这样做:
```
@Bean
public IntegrationFlow splitRouteAggregate() {
return f -> f
.split()
.route(o -> o % 2 == 0,
m -> m
.subFlowMapping(true, oddFlow())
.subFlowMapping(false, sf -> sf.gateway(evenFlow())))
.aggregate();
}
@Bean
public IntegrationFlow oddFlow() {
return f -> f.handle(m -> System.out.println("odd"));
}
@Bean
public IntegrationFlow evenFlow() {
return f -> f.handle((p, h) -> "even");
}
```
在这种情况下,当你需要从这样的子流收到回复并继续主流时,这个`IntegrationFlow` Bean 引用(或其输入通道)必须用`.gateway()`进行包装,如前面的示例所示。
前面示例中的`oddFlow()`引用没有包装到`.gateway()`。
因此,我们不期望从这个路由分支得到答复。
否则,你最终会遇到一个类似于以下情况的异常:
```
Caused by: org.springframework.beans.factory.BeanCreationException:
The 'currentComponent' ([email protected]a51c)
is a one-way 'MessageHandler' and it isn't appropriate to configure 'outputChannel'.
This is the end of the integration flow.
```
当你将一个子流配置为 lambda 时,框架将处理与子流的请求-回复交互,并且不需要网关。|
+|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+子流可以嵌套到任何深度,但我们不建议这样做。事实上,即使是在路由器的情况下,在一个流中添加复杂的子流,很快就会开始看起来像一盘意大利面条,并且对于人类来说很难进行解析。
+
+| |在 DSL 支持子流配置的情况下,当所配置的组件通常需要一个通道,并且该子流以`channel()`元素开始时,框架会隐式地在组件输出通道和流的输入通道之间放置一个`bridge()`。,例如,在这个`filter`定义中:
```
.filter(p -> p instanceof String, e -> e
.discardFlow(df -> df
.channel(MessageChannels.queue())
...)
```
框架内部创建了一个`DirectChannel` Bean 用于注入`MessageFilter.discardChannel`。
然后它将子流包装到一个`IntegrationFlow`中,从这个隐式通道开始,用于订阅并在流中指定的`channel()`之前放置一个`bridge`。
当现有的`IntegrationFlow` Bean 被用作子流引用(而不是内置子流,例如 lambda)时,没有这样的桥需要,因为框架可以解析来自第一通道的流 Bean。具有内联子流的输入通道尚不可用。|
+|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+### [](#java-dsl-protocol-adapters)使用协议适配器
+
+到目前为止所示的所有示例都说明了 DSL 如何通过使用 Spring 集成编程模型来支持消息传递体系结构。然而,我们还没有进行任何真正的整合。这样做需要通过 HTTP、JMS、AMQP、TCP、JDBC、FTP、SMTP 等访问远程资源,或者访问本地文件系统。 Spring 集成支持所有这些和更多内容。理想情况下,DSL 应该为所有这些功能提供一流的支持,但是实现所有这些功能并随着新的适配器被添加到 Spring 集成中而跟上,这是一项艰巨的任务。因此,期望是 DSL 不断赶上 Spring 集成。
+
+因此,我们提供了高级 API 来无缝地定义特定于协议的消息传递。我们用工厂和建造商的模式以及 lambdas 来实现这一点。你可以将工厂类视为“命名空间工厂”,因为它们与来自具体协议特定的 Spring 集成模块的组件的 XML 命名空间扮演相同的角色。目前, Spring 集成 Java DSL 支持`Amqp`、`Feed`、`Jms`、`Files`、`(S)Ftp`、`Http`、`JPA`、`TCP/UDP`、`Mail`、和`Scripts`名称空间工厂。下面的示例显示了如何使用其中的三个(`Amqp`,`Jms`和`Mail`):
+
+```
+@Bean
+public IntegrationFlow amqpFlow() {
+ return IntegrationFlows.from(Amqp.inboundGateway(this.rabbitConnectionFactory, queue()))
+ .transform("hello "::concat)
+ .transform(String.class, String::toUpperCase)
+ .get();
+}
+
+@Bean
+public IntegrationFlow jmsOutboundGatewayFlow() {
+ return IntegrationFlows.from("jmsOutboundGatewayChannel")
+ .handle(Jms.outboundGateway(this.jmsConnectionFactory)
+ .replyContainer(c ->
+ c.concurrentConsumers(3)
+ .sessionTransacted(true))
+ .requestDestination("jmsPipelineTest"))
+ .get();
+}
+
+@Bean
+public IntegrationFlow sendMailFlow() {
+ return IntegrationFlows.from("sendMailChannel")
+ .handle(Mail.outboundAdapter("localhost")
+ .port(smtpPort)
+ .credentials("user", "pw")
+ .protocol("smtp")
+ .javaMailProperties(p -> p.put("mail.debug", "true")),
+ e -> e.id("sendMailEndpoint"))
+ .get();
+}
+```
+
+前面的示例展示了如何使用“名称空间工厂”作为内联适配器声明。但是,你可以从`@Bean`定义中使用它们,以使`IntegrationFlow`方法链更具可读性。
+
+| |我们正在征求社区对这些命名空间工厂的反馈意见,然后再将精力花在其他工厂上。
我们还感谢对优先级排序的任何输入,我们下一步应该支持哪些适配器和网关。|
+|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+你可以在整个参考手册中的特定于协议的章节中找到更多的 Java DSL 示例。
+
+所有其他协议通道适配器可以被配置为通用 bean 并连接到`IntegrationFlow`,如下例所示:
+
+```
+@Bean
+public QueueChannelSpec wrongMessagesChannel() {
+ return MessageChannels
+ .queue()
+ .wireTap("wrongMessagesWireTapChannel");
+}
+
+@Bean
+public IntegrationFlow xpathFlow(MessageChannel wrongMessagesChannel) {
+ return IntegrationFlows.from("inputChannel")
+ .filter(new StringValueTestXPathMessageSelector("namespace-uri(/*)", "my:namespace"),
+ e -> e.discardChannel(wrongMessagesChannel))
+ .log(LoggingHandler.Level.ERROR, "test.category", m -> m.getHeaders().getId())
+ .route(xpathRouter(wrongMessagesChannel))
+ .get();
+}
+
+@Bean
+public AbstractMappingMessageRouter xpathRouter(MessageChannel wrongMessagesChannel) {
+ XPathRouter router = new XPathRouter("local-name(/*)");
+ router.setEvaluateAsString(true);
+ router.setResolutionRequired(false);
+ router.setDefaultOutputChannel(wrongMessagesChannel);
+ router.setChannelMapping("Tags", "splittingChannel");
+ router.setChannelMapping("Tag", "receivedChannel");
+ return router;
+}
+```
+
+### [](#java-dsl-flow-adapter)`IntegrationFlowAdapter`
+
+`IntegrationFlow`接口可以直接实现并指定为用于扫描的组件,如下例所示:
+
+```
+@Component
+public class MyFlow implements IntegrationFlow {
+
+ @Override
+ public void configure(IntegrationFlowDefinition> f) {
+ f.transform(String::toUpperCase);
+ }
+
+}
+```
+
+它由`IntegrationFlowBeanPostProcessor`拾取,并在应用程序上下文中进行了正确的解析和注册。
+
+为了方便和获得松耦合体系结构的好处,我们提供了`IntegrationFlowAdapter`基类实现。它需要一个`buildFlow()`方法实现来通过使用`from()`方法中的一个来生成`IntegrationFlowDefinition`方法,如下例所示:
+
+```
+@Component
+public class MyFlowAdapter extends IntegrationFlowAdapter {
+
+ private final AtomicBoolean invoked = new AtomicBoolean();
+
+ public Date nextExecutionTime(TriggerContext triggerContext) {
+ return this.invoked.getAndSet(true) ? null : new Date();
+ }
+
+ @Override
+ protected IntegrationFlowDefinition> buildFlow() {
+ return from(this::messageSource,
+ e -> e.poller(p -> p.trigger(this::nextExecutionTime)))
+ .split(this)
+ .transform(this)
+ .aggregate(a -> a.processor(this, null), null)
+ .enrichHeaders(Collections.singletonMap("thing1", "THING1"))
+ .filter(this)
+ .handle(this)
+ .channel(c -> c.queue("myFlowAdapterOutput"));
+ }
+
+ public String messageSource() {
+ return "T,H,I,N,G,2";
+ }
+
+ @Splitter
+ public String[] split(String payload) {
+ return StringUtils.commaDelimitedListToStringArray(payload);
+ }
+
+ @Transformer
+ public String transform(String payload) {
+ return payload.toLowerCase();
+ }
+
+ @Aggregator
+ public String aggregate(List payloads) {
+ return payloads.stream().collect(Collectors.joining());
+ }
+
+ @Filter
+ public boolean filter(@Header Optional thing1) {
+ return thing1.isPresent();
+ }
+
+ @ServiceActivator
+ public String handle(String payload, @Header String thing1) {
+ return payload + ":" + thing1;
+ }
+
+}
+```
+
+### [](#java-dsl-runtime-flows)动态和运行时集成流
+
+`IntegrationFlow`及其所有相关组件都可以在运行时注册。在版本 5.0 之前,我们使用`BeanFactory.registerSingleton()`钩子。从 Spring 框架`5.0`开始,我们使用`instanceSupplier`钩子进行程序化的`BeanDefinition`注册。下面的示例显示了如何以编程方式注册 Bean:
+
+```
+BeanDefinition beanDefinition =
+ BeanDefinitionBuilder.genericBeanDefinition((Class