此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 spring-cloud-stream 4.1.4! |
Mechanics
为了更好地理解内容类型协商背后的机制和必要性,我们使用以下消息处理程序作为示例来查看一个非常简单的用例:
public Function<Person, String> personFunction {..}
为简单起见,我们假设这是应用程序中唯一的处理程序函数(我们假设没有内部管道)。 |
前面示例中显示的处理程序需要一个Person
object 作为参数,并生成一个String
type 作为输出。
为了使框架成功传递传入的Message
作为此处理程序的参数,它必须以某种方式转换Message
type 从 Wire 格式转换为Person
类型。
换句话说,框架必须找到并应用适当的MessageConverter
.
为此,框架需要用户提供一些说明。
这些指令之一已经由处理程序方法本身的签名 (Person
type) 的 intent 的 intent
因此,从理论上讲,这应该(而且在某些情况下是)足够了。
但是,对于大多数使用案例,为了选择合适的MessageConverter
,框架需要一条额外的信息。
缺失的部分是contentType
.
Spring Cloud Stream 提供了三种机制来定义contentType
(按优先顺序):
-
HEADER的
contentType
可以通过 Message 本身进行通信。通过提供contentType
标头中,请声明用于查找和应用相应MessageConverter
. -
BINDING的
contentType
可以通过设置spring.cloud.stream.bindings.input.content-type
财产。这 input
segment 对应于目标的实际名称(在本例中为 “input”)。此方法允许您基于每个绑定声明用于查找和应用适当的MessageConverter
. -
默认值:如果
contentType
不存在于Message
header 或 Binding,则默认的application/json
content 类型用于 找到并应用适当的MessageConverter
.
如前所述,前面的列表还演示了平局情况下的优先顺序。例如,标头提供的内容类型优先于任何其他内容类型。 这同样适用于基于每个绑定设置的内容类型,这实质上允许您覆盖默认内容类型。 但是,它也提供了一个合理的默认值(这是根据社区反馈确定的)。
制作application/json
默认值源于分布式微服务架构驱动的互作性要求,其中生产者和使用者不仅运行在不同的 JVM 中,而且可以在不同的非 JVM 平台上运行。
当非 void 处理程序方法返回时,如果返回值已经是Message
那Message
变为负载。但是,当返回值不是Message
,则新的Message
在继承时以返回值作为有效负载构造
标头Message
减去定义或筛选的标头SpringIntegrationProperties.messageHandlerNotPropagatedHeaders
.
默认情况下,那里只有一个标头集:contentType
.这意味着新的Message
没有contentType
标头集,从而确保contentType
可以进化。
您始终可以选择不返回Message
从 handler 方法中,您可以在其中注入所需的任何标头。
如果存在内部管道,则Message
通过相同的转换过程发送到下一个处理程序。但是,如果没有内部管道,或者您已到达内部管道的末尾,则Message
将发送回输出目标。
内容类型与参数类型
如前所述,对于框架选择适当的MessageConverter
,它需要参数类型和内容类型信息(可选)。
选择适当MessageConverter
驻留在参数 resolvers (HandlerMethodArgumentResolvers
),该方法在调用用户定义的处理程序方法之前触发(即当框架知道实际参数类型时)。
如果参数类型与当前有效负载的类型不匹配,则框架会将
预配置MessageConverters
查看它们中的任何一个是否可以转换有效负载。
如您所见,Object fromMessage(Message<?> message, Class<?> targetClass);
MessageConverter 的作需要targetClass
作为其参数之一。
该框架还确保提供的Message
始终包含一个contentType
页眉。
当不存在 contentType 标头时,它会注入每个绑定的contentType
header 或默认的contentType
页眉。
的组合contentType
Argument Type 是框架确定 message 是否可以转换为目标类型的机制。
如果没有合适的MessageConverter
,则会引发异常,您可以通过添加自定义MessageConverter
(参见User-defined Message Converters
).
但是,如果有效负载类型与处理程序方法声明的目标类型匹配,该怎么办?在这种情况下,没有要转换的内容,并且
payload 的 Payload 传递时未修改。虽然这听起来非常简单且合乎逻辑,但请记住,采用Message<?>
或Object
作为参数。
通过将目标类型声明为Object
(即instanceof
所有内容都在 Java 中),您基本上就放弃了转换过程。
不要指望Message 仅根据contentType .
请记住,contentType 是对 target 类型的补充。
如果您愿意,您可以提供一个提示,即MessageConverter 可能会也可能不会考虑。 |
消息转换器
MessageConverters
定义两个方法:
Object fromMessage(Message<?> message, Class<?> targetClass);
Message<?> toMessage(Object payload, @Nullable MessageHeaders headers);
了解这些方法的 Contract 及其用法非常重要,特别是在 Spring Cloud Stream 的上下文中。
这fromMessage
方法将传入的Message
转换为参数类型。
的Message
可以是任何类型,并且是
直到实际实现MessageConverter
以支持多种类型。
例如,某些 JSON 转换器可能支持将有效负载类型作为byte[]
,String
等。
当应用程序包含内部管道(即输入 → handler1 → handler2 →时,这一点非常重要。 . . .→ 输出),并且上游处理程序的输出会生成一个Message
这可能不是初始连线格式。
但是,toMessage
method 具有更严格的 Contract ,并且必须始终转换Message
设置为连线格式:byte[]
.
因此,对于所有意图和目的(尤其是在实现您自己的转换器时),您将这两个方法视为具有以下签名:
Object fromMessage(Message<?> message, Class<?> targetClass);
Message<byte[]> toMessage(Object payload, @Nullable MessageHeaders headers);