Spring Cloud Stream 2.0 - 内容类型协商和转换

工程 | Oleg Zhurakousky | 2018年2月26日 | ...

这是 Spring Cloud Stream 2.0.0.RELEASE 发布准备工作中的一系列预发布博客中的第一篇。

前言

Spring Cloud Stream 2.0 包含对基于通道的绑定器的内容类型协商的全面改进,以解决性能、灵活性和最重要的是一致性问题。以下博客探讨了已完成的一些关键点、期望的内容以及它可能如何帮助您。

简介

数据转换是任何消息驱动微服务架构的核心功能之一。在 Spring Cloud Stream 中,此类数据表示为 Spring 的Message

在消息流(一个流)的各个点,可能需要将消息转换为所需的形状/大小,然后再到达其目标。这是由于两个原因造成的

1. 将传入消息的内容线格式转换为与应用程序提供的处理程序签名匹配。2. 将传出消息的内容转换为下一个处理程序的签名(如果存在某些内部流)或转换回线格式。

线格式通常为byte[],并由绑定器实现控制。

在 Spring Cloud Stream 消息中,转换是通过org.springframework.messaging.converter.MessageConverter抽象来完成的。

以下步骤序列显示了典型消息流以及Message经历的转换,使用 Spring Cloud Stream 的Processor契约进行了描述,基本上涵盖了入站出站内容转换背后的需求。

1. 从绑定器接收线格式的 Spring Message 2. 确保在 Spring Message 中设置了输入contentType标头 3. 将 Spring Message线格式转换为应用程序提供的MessageHandler的签名 4. 调用应用程序提供的MessageHandler 5. 将MessageHandler的返回值转换回 Spring Message 6. 确保在 Spring Message 中设置了输出contentType标头 7. 将 Spring Message转换回线格式 8. 将线格式的 Spring Message发送回绑定器

虽然以上内容提供了典型消息流中主要状态变化的完整摘要,但细节总是很重要的,因此让我们更仔细地查看每个步骤。

细节

  1. 传入消息由绑定器接收,并以线格式发送到绑定器的输入通道(例如,Processor.INPUT')。
  2. 内部输入通道预先配置了通道拦截器,用于仅当传入消息尚未设置contentType标头时才向传入消息注入contentType标头。这是为了确保,如果需要,下游消息转换可以考虑contentType(稍后将详细介绍)。注入的contentType来自为每个目标绑定设置的内容类型,其中application/json为默认内容类型。

例如,'spring.cloud.stream.bindings.myInput.content-type=text/plain' 将目标绑定'myInput'(传入)的内容类型设置为'text/plain'。这意味着除非消息已包含'contentType'标头,否则每个传入消息都会注入'contentType=text/plain'标头。换句话说,标头提供的contentType优先于每个绑定设置的标头。3. 现在,借助HandlerMethodArgumentResolvers和预配置或用户提供的MessageConverters,传入消息将转换为应用程序提供的MessageHandler的签名(例如,public Text process(Foo foo){..})。此类处理程序方法通常使用@StreamListener@ServiceActivator@Transformer等其中一个进行注释。这就是一些转换器可能需要contentType的地方,并且步骤 2 中的操作保证此类消息始终可以通过其contentType标头获得它。当然,如果此类方法将Message作为其输入参数,则不会执行转换。4. 处理程序方法被调用,并且成功后,将从处理程序方法的返回值开始创建传出消息的过程(假设非空处理程序方法)。5. 处理程序方法返回的值将转换回 Spring Message,当且仅当返回值本身不是Message时。这意味着将使用处理程序的返回值作为有效负载创建一个新的 Spring Message。传入消息的标头将复制到新的传出消息中,同时剥离'SpringIntegrationProperties.messageHandlerNotPropagatedHeaders'标识的任何标头。默认情况下,只有一个标头设置在那里 - contentType。这意味着新的传出消息是在没有设置contentType标头的情况下创建的。这是为了确保contentType可以随着应用程序级数据转换而发展。注意:仅当处理程序方法返回非 Message 时才会剥离contentType消息将发送到绑定器的输出通道。6. 与绑定器的输入通道类似,绑定器的输出通道(例如,Processor.OUTPUT)也预先配置了通道拦截器。在这里,我们可选地将contentType标头注入传出消息中,以准备将传出消息的内容转换回线格式。让我们看看仅有的两种可能的情况:a. 传出 Message 设置了contentType标头。由于标头设置的contentType优先于任何其他contentType,因此不会执行任何contentType注入,并且标头设置的contentType的值将在转换回线格式期间使用。b. 传出 Message 未设置contentType标头。绑定contentType(默认或提供)将作为标头注入传出消息中,并在转换回线格式期间使用。7. 使用可用的MessageConverters之一将消息转换为线格式。8. 转换后的消息将发送回绑定器,同时保留注入的或现有的contentType标头。换句话说,传出消息将始终具有contentType标头。

自定义

以上内容涵盖了开箱即用的默认行为。但这可能还不够,所以我们能否以及如何自定义?。2.0 中进行的内容类型协商改进的目标不仅是为了回答此类问题,而且是为了确保答案的一致性 - 入站出站通道拦截器用于转换为/从线格式的'MessageConverters'与'HandlerMethodArgumentResolvers'用于转换为/从强类型转换的'MessageConverters'相同

要添加自定义MessageConverter,只需创建org.springframework.messaging.converter.MessageConverter的实现,并将其配置为@Bean,并将该 bean 注释为@StreamMessageConverter,它将作为现有MessageConverters堆栈中的第一个转换器添加,基本上优先于现有的MessageConverters

总结

希望到目前为止,任何和所有内容类型转换都是由MessageConverters完成的这一点已经相当清楚了。虽然MessageConverters的实现有所不同,但大多数都利用contentType标头以及目标类型(targetClass),这使它们能够执行类型内转换以及到/从线格式的转换。目前有一组预配置的MessageConverters来支持大多数用例,因此对于大多数典型数据类型(即 json、文本等),最终用户实际上无需执行任何操作。但是,了解现在的工作原理与如何自定义之间的区别仍然很有价值 - 自定义现有和/或引入新的MessageConverter实现

结论

我们目前正在更新文档,其中将包含更多关于此主题以及许多其他与 2.0 版本相关工作的详细信息和示例。这些预发布博文的目的是提高认知度,促进“试用”并征求反馈。综上所述,Spring Cloud Stream 2.0.0.RC1 已发布,您可以点击此处获取。

我们鼓励您使用以下方式提供反馈:

祝您使用愉快!

获取 Spring Newsletter

关注 Spring Newsletter

订阅

抢先一步

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

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一个简单的订阅即可。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部