Spring Integration Java DSL 里程碑 2 发布

发布 | Artem Bilan | 2014 年 6 月 18 日 | ...

我们很高兴宣布,用于 Spring Integration 的 Java DSL 扩展的**第二个里程碑版本**已经发布!

构件 org.springframework.integration:spring-integration-java-dsl:1.0.0.M2 可从 Spring IO 里程碑仓库获取。

里程碑 2 包含了一些错误修复、一些新特性和进一步改进。

感谢所有尝试了里程碑 1、提供了反馈、提出了问题并分享了想法的人们。

以下是自 里程碑 1 以来的主要变更摘要

Lambda 处理器

正如您可能已经注意到的,使用 Java 8 Lambdas 是使这个 DSL 方便易读的强大工具。我们收到的一个社区请求是允许为 .handle() EIP 方法声明一个 Lambda,而不是必须声明一个 POJO 并将其用作方法调用。但一个担忧是不要丢失“运行时类型转换”。然而,您无法获取 Lambda 的泛型类型。经过一些调查,我们通过添加一个 type 参数找到了解决方案。因此,已向 IntegrationFlowBuilder 添加了一些新方法


<P> IntegrationFlowBuilder handle(GenericHandler<P> handler)

<P> IntegrationFlowBuilder handle(GenericHandler<P> handler,
		EndpointConfigurer<GenericEndpointSpec<ServiceActivatingHandler>> endpointConfigurer) 


<P> IntegrationFlowBuilder handle(Class<P> payloadType, GenericHandler<P> handler)

<P> IntegrationFlowBuilder handle(Class<P> payloadType, GenericHandler<P> handler,
		EndpointConfigurer<GenericEndpointSpec<ServiceActivatingHandler>> endpointConfigurer)

如果您使用带有显式 payloadType 参数且 handler 是 Lambda 的方法变体,最后一个参数将封装到带有 ConversionServiceLambdaMessageProcessor 中。消息的 payload 将在运行时转换为适当的 type。通过这种方式,我们实现了更好的松耦合。这里有一个简单的示例来演示

@Bean
public IntegrationFlow integerFlow() {
	return IntegrationFlows.from("input")
			.<byte[], String>transform(p - > new String(p, "UTF-8"))
			.handle(Integer.class, (p, h) -> p * 2)
			.get();
}

ConversionService 可以防止 ClassCastException: String cannot be cast to Integer 错误。

同样附加的类型参数已添加到带有 Lambdas 的其他 EIP 方法中:.transform().filter().split() 等。

转换器工厂

已添加方便、流畅的 Transformers 工厂,可在 .transform() EIP 方法中用作内联目标对象定义

@Bean
public IntegrationFlow transformFlow() {
	return IntegrationFlows.from("input")
			.transform(Transformers.xpath("/root/myJson", XPathEvaluationType.STRING_RESULT))
			.transform(Transformers.fromJson(MyPojo.class))
			.transform(Transformers.serializer())
			.get();
}

它避免了使用 setter 的不便编码,并使流定义更加直观。请注意,Transformers 可用于将目标 Transformer 声明为 @Bean,并再次从 IntegrationFlow 定义中使用它们。然而,如果内联对象尚未定义为 bean,DSL 解析器会负责处理它们的 bean 声明。

.gateway() EIP 方法

由于 IntegrationFlow 定义看起来类似于 Spring Integration XML 中的 <chain>,我们引入了 .gateway() EIP 方法,它在 <chain> 中扮演与 <gateway> 相同的角色——将消息发送到另一个消息流的 requestChannel,并等待从其 replyChannel 或默认的 TemporaryReplyChannel 获取结果

@Bean
@DependsOn("gatewayRequestFlow")
public IntegrationFlow gatewayFlow() {
	return IntegrationFlows.from("gatewayInput")
			.gateway("gatewayRequest", g -> g.errorChannel("gatewayError").replyTimeout(10L))
			.get();
}

@Bean
public IntegrationFlow gatewayRequestFlow() {
	return IntegrationFlows.from("gatewayRequest")
			.filter("foo"::equals, f -> f.throwExceptionOnRejection(true))
			.<String, String>transform(String::toUpperCase)
			.get();
}

特定协议适配器

当然,Spring Integration 的大部分价值体现在与某些外部系统的交互,协议适配器提供了这种功能。使用 Spring Integration Java DSL,我们可以继续对任何终端系统适配器(例如 MarshallingWebServiceInboundGateway)使用通用的 bean 定义(@Bean),但 DSL 的目的是提供更高级别的 API,以类似于 Spring Integration XML 配置的方式声明组件。

既然您已经熟悉了我们的 BuilderLambda 功能,我们将在此基础上构建。已经引入了一些类,它们带有一组静态方法,用于委托给底层的一些 IntegrationComponentSpec<S, P> 实现。这些类可以被视为“命名空间工厂”,因为它们对于来自具体协议特定的 Spring Integration 模块的组件来说,扮演着与 XML 命名空间相同的角色。目前,Spring Integration Java DSL 仅支持 AmqpJms 命名空间工厂

@Bean
public IntegrationFlow amqpFlow() {
	return IntegrationFlows.from(Amqp.inboundGateway(this.rabbitConnectionFactory, queue()))
			.transform("hello "::concat)
			.transform(String.class, String::toUpperCase)
			.get();
}

@Bean
public IntegrationFlow amqpOutboundFlow() {
	return IntegrationFlows.from("amqpOutboundInput")
            .handle(Amqp.outboundAdapter(this.amqpTemplate).routingKeyExpression("headers.routingKey"))
			.get();
}

@Bean
public IntegrationFlow jmsInboundFlow() {
	return IntegrationFlows
			.from(Jms.inboundAdapter(this.jmsConnectionFactory)
					.configureJmsTemplate(t ->
							t.deliveryPersistent(true)
									.jmsMessageConverter(myMessageConverter()))
					.destination("jmsInbound"))
			.<String, String>transform(String::toUpperCase)
			.channel(this.jmsOutboundInboundReplyChannel())
			.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 定义中使用,以使 IntegrationFlow 方法链更具可读性。

在我们将精力投入到其他工厂之前,我们正在征集社区对这些命名空间工厂的反馈;我们也很希望了解接下来我们应该优先支持哪些适配器/网关。

请确保您的 classpath 中有具体的 spring-integration-[PROTOCOL].jar 及其必需的依赖项,因为 spring-integration-java-dsl 将它们声明为 optional,以避免不必要的终端应用程序开销。

DSL 解析器变更

然而,这次 M2 版本的主要目的是解决 DSL 解析器位置错误的严重问题。现在它已从 IntegrationConfigurationBeanFactoryPostProcessor 移至 IntegrationFlowBeanPostProcessor,Spring Integration Java DSL 不再影响应用程序上下文——它仅遵循标准的 Spring bean 定义生命周期。您可能需要对现有的 DSL 应用程序进行一些更改才能使用此版本。

在大多数情况下,这仅限于 channel auto-declaration,即我们没有定义显式的 MessageChannel bean 定义,而是从集成组件中引用它。如果您注意到上面的 .gateway() 示例中我们使用了 @DependsOn 注解。这是因为 bean 是在 @Configuration 类中声明时逐个注册和初始化的。由于我们没有为 MessageChannel 使用 bean 定义,应用程序上下文无法自动为使用 channel 的 bean 声明 dependsOn,而且从另一方面来说,我们根本没有声明 MessageChannel bean,我们只有一个选择就是依赖于 IntegrationFlow bean。

因此,您可以选择显式声明 MessageChannel bean,或者在声明隐式 channel 的下游 IntegrationFlow 的相应 IntegrationFlow bean 定义上使用 @DependsOn

总结

请参阅上面提到的参考手册以获取更多信息。并查看 [网络研讨会回放:Spring Integration 4.0 - 新领域] (https://springjava.cn/blog/2014/05/15/webinar-replay-spring-integration-4-0-the-new-frontier),其中通过“实时编码”介绍了 Spring Integration Java DSL。

照例:请随时分享您的想法和反馈:StackOverflow (spring-integration 标签),Spring JIRA

SpringOne 2GX 2014 即将到来

请尽快预订 9 月 8-11 日在德克萨斯州达拉斯举行的 SpringOne2GX 的席位。这绝对是第一手了解最新动态并提供直接反馈的最佳机会。预计今年将有许多重要的新公告。我们预计将有几个深入的 Spring Integration 会议。

获取 Spring 新闻通讯

订阅 Spring 新闻通讯,保持联系

订阅

先人一步

VMware 提供培训和认证,助您快速提升。

了解更多

获取支持

Tanzu Spring 通过一项简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部