DSL 基础
org.springframework.integration.dsl
包包含前面提到的 IntegrationFlowBuilder
API 和许多 IntegrationComponentSpec
实现,它们也是构建器,并提供了配置具体端点的流畅 API。
IntegrationFlowBuilder
基础设施为基于消息的应用程序提供了通用的 企业集成模式 (EIP),例如通道、端点、轮询器和通道拦截器。
- IMPORTANT
-
IntegrationComponentSpec
是FactoryBean
实现,因此其getObject()
方法不得从 bean 定义中调用。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>
实例。
因此,此处可以使用任何提供的转换器(ObjectToJsonTransformer
、FileToStringTransformer
等)。
在底层,IntegrationFlowBuilder
识别 MessageHandler
及其端点,分别使用 MessageTransformingHandler
和 ConsumerEndpointFactoryBean
。
考虑另一个例子:
@Bean
public IntegrationFlow myFlow() {
return IntegrationFlow.from("input")
.filter("World"::equals)
.transform("Hello "::concat)
.handle(System.out::println)
.get();
}
前面的示例组合了一个 Filter → Transformer → Service Activator
序列。
该流是“单向”的。
也就是说,它不提供回复消息,只将负载打印到标准输出。
端点通过使用直接通道自动连接在一起。
Message<?>
参数在 EIP 方法中使用 lambda 时,“输入”参数通常是消息负载。
如果您希望访问整个消息,请使用其中一个将 Class<?>
作为第一个参数的重载方法。
例如,这不起作用:
.<Message<?>, Foo>transform(m -> newFooFromMessage(m))
这将在运行时因 ClassCastException
而失败,因为 lambda 不会保留参数类型,并且框架将尝试将负载转换为 Message<?>
。
相反,使用:
.(Message.class, m -> newFooFromMessage(m))
Java DSL 可以为流定义中内联定义的对象注册 bean,也可以重用现有的、注入的 bean。
如果内联对象和现有 bean 定义定义了相同的 bean 名称,则会抛出 BeanDefinitionOverrideException
,表示此类配置是错误的。
但是,当您处理 prototype
bean 时,无法从集成流处理器检测到现有 bean 定义,因为每次我们从 BeanFactory
调用 prototype
bean 时,我们都会得到一个新的实例。
这样,提供的实例在 IntegrationFlow
中按原样使用,没有任何 bean 注册,也没有任何可能针对现有 prototype
bean 定义的检查。
但是,如果此对象具有显式 id
并且此名称的 bean 定义在 prototype
作用域中,则会为此对象调用 BeanFactory.initializeBean()
。