跳到主要内容
版本:7.0.2

DSL 基础

DeepSeek V3 中英对照 DSL Basics

org.springframework.integration.dsl 包包含之前提到的 IntegrationFlowBuilder API 以及许多 IntegrationComponentSpec 实现,这些实现同样作为构建器,提供了用于配置具体端点的流式 API。IntegrationFlowBuilder 基础设施为基于消息的应用程序提供了常见的企业集成模式(EIP),例如通道、端点、轮询器和通道拦截器。

重要

IntegrationComponentSpec 是一个 FactoryBean 实现,因此不得从 bean 定义中调用其 getObject() 方法。IntegrationComponentSpec 实现必须保持原样用于 bean 定义,框架将管理其生命周期。对于 IntegrationFlow bean 定义,必须使用针对目标 IntegrationComponentSpec 类型(一个 FactoryBean 值)的 bean 方法参数注入,而不是 bean 方法引用。

在DSL中,端点以动词形式表示以提高可读性。以下列表包含了常见的DSL方法名称及其关联的EIP端点:

  • transform → Transformer

  • filter → Filter

  • handle → ServiceActivator

  • split → Splitter

  • aggregate → Aggregator

  • route → Router

  • bridge → Bridge

从概念上讲,集成流程是通过将这些端点组合成一个或多个消息流来构建的。请注意,EIP并未正式定义"消息流"这一术语,但将其视为使用已知消息传递模式的工作单元是有益的。DSL提供了一个IntegrationFlow组件来定义通道及其间端点的组合,但现在IntegrationFlow仅扮演配置角色,用于在应用程序上下文中填充实际的bean,在运行时并不使用。不过,IntegrationFlow的bean可以作为Lifecycle自动装配,以控制整个流程的start()stop(),这些操作会委托给与此IntegrationFlow关联的所有Spring Integration组件。以下示例使用IntegrationFlow流式API,通过IntegrationFlowBuilder中的EIP方法来定义IntegrationFlow bean:

@Bean
public IntegrationFlow integerFlow() {
return IntegrationFlow.from("input")
.<String, Integer>transform(Integer::parseInt)
.get();
}

transform 方法接受一个 lambda 表达式作为端点参数,用于操作消息负载。该方法的实际参数是一个 GenericTransformer<S, T> 实例。因此,任何提供的转换器(如 ObjectToJsonTransformerFileToStringTransformer 等)都可以在此处使用。

在底层实现中,IntegrationFlowBuilder 能够识别 MessageHandler 及其对应的端点,分别通过 MessageTransformingHandlerConsumerEndpointFactoryBean 实现。请看另一个示例:

@Bean
public IntegrationFlow myFlow() {
return IntegrationFlow.from("input")
.filter("World"::equals)
.transform("Hello "::concat)
.handle(System.out::println)
.get();
}

前面的示例组合了一个 Filter → Transformer → Service Activator 的序列。该流程是"单向的"。也就是说,它不提供回复消息,而只是将有效负载打印到 STDOUT。通过使用直接通道,端点被自动连接在一起。

important

Lambda 表达式与 Message<?> 参数

在 EIP 方法中使用 lambda 表达式时,"input" 参数通常是消息的有效负载。如果您希望访问完整的消息,请使用接受 Class<?> 作为第一个参数的重载方法。例如,以下代码将无法正常工作:

.<Message<?>, Foo>transform(m -> newFooFromMessage(m))

这将在运行时因 ClassCastException 而失败,因为 lambda 表达式未保留参数类型,框架将尝试将有效负载强制转换为 Message<?>

请改用以下方式:

.(Message.class, m -> newFooFromMessage(m))
important

Bean 定义覆盖

Java DSL 可以为流程定义中内联定义的对象注册 bean,也可以重用已注入的现有 bean。如果为内联对象和现有 bean 定义定义了相同的 bean 名称,则会抛出 BeanDefinitionOverrideException,表明此类配置是错误的。然而,当处理 prototype 作用域的 bean 时,无法从集成流处理器检测到现有的 bean 定义,因为每次我们从 BeanFactory 调用 prototype bean 时,都会获得一个新实例。因此,提供的实例在 IntegrationFlow 中按原样使用,无需进行任何 bean 注册,也无需对现有的 prototype bean 定义进行任何可能的检查。但是,如果该对象具有显式的 id 并且该名称的 bean 定义处于 prototype 作用域,则会为此对象调用 BeanFactory.initializeBean()