此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 spring-cloud-stream 4.1.4spring-doc.cadn.net.cn

Mechanics

为了更好地理解内容类型协商背后的机制和必要性,我们使用以下消息处理程序作为示例来查看一个非常简单的用例:spring-doc.cadn.net.cn

public Function<Person, String> personFunction {..}
为简单起见,我们假设这是应用程序中唯一的处理程序函数(我们假设没有内部管道)。

前面示例中显示的处理程序需要一个Personobject 作为参数,并生成一个Stringtype 作为输出。 为了使框架成功传递传入的Message作为此处理程序的参数,它必须以某种方式转换Messagetype 从 Wire 格式转换为Person类型。 换句话说,框架必须找到并应用适当的MessageConverter. 为此,框架需要用户提供一些说明。 这些指令之一已经由处理程序方法本身的签名 (Persontype) 的 intent 的 intent 因此,从理论上讲,这应该(而且在某些情况下是)足够了。 但是,对于大多数使用案例,为了选择合适的MessageConverter,框架需要一条额外的信息。 缺失的部分是contentType.spring-doc.cadn.net.cn

Spring Cloud Stream 提供了三种机制来定义contentType(按优先顺序):spring-doc.cadn.net.cn

  1. HEADERcontentType可以通过 Message 本身进行通信。通过提供contentType标头中,请声明用于查找和应用相应MessageConverter.spring-doc.cadn.net.cn

  2. BINDINGcontentType可以通过设置spring.cloud.stream.bindings.input.content-type财产。spring-doc.cadn.net.cn

    inputsegment 对应于目标的实际名称(在本例中为 “input”)。此方法允许您基于每个绑定声明用于查找和应用适当的MessageConverter.
  3. 默认值:如果contentType不存在于Messageheader 或 Binding,则默认的application/jsoncontent 类型用于 找到并应用适当的MessageConverter.spring-doc.cadn.net.cn

如前所述,前面的列表还演示了平局情况下的优先顺序。例如,标头提供的内容类型优先于任何其他内容类型。 这同样适用于基于每个绑定设置的内容类型,这实质上允许您覆盖默认内容类型。 但是,它也提供了一个合理的默认值(这是根据社区反馈确定的)。spring-doc.cadn.net.cn

制作application/json默认值源于分布式微服务架构驱动的互作性要求,其中生产者和使用者不仅运行在不同的 JVM 中,而且可以在不同的非 JVM 平台上运行。spring-doc.cadn.net.cn

当非 void 处理程序方法返回时,如果返回值已经是MessageMessage变为负载。但是,当返回值不是Message,则新的Message在继承时以返回值作为有效负载构造 标头Message减去定义或筛选的标头SpringIntegrationProperties.messageHandlerNotPropagatedHeaders. 默认情况下,那里只有一个标头集:contentType.这意味着新的Message没有contentType标头集,从而确保contentType可以进化。 您始终可以选择不返回Message从 handler 方法中,您可以在其中注入所需的任何标头。spring-doc.cadn.net.cn

如果存在内部管道,则Message通过相同的转换过程发送到下一个处理程序。但是,如果没有内部管道,或者您已到达内部管道的末尾,则Message将发送回输出目标。spring-doc.cadn.net.cn

内容类型与参数类型

如前所述,对于框架选择适当的MessageConverter,它需要参数类型和内容类型信息(可选)。 选择适当MessageConverter驻留在参数 resolvers (HandlerMethodArgumentResolvers),该方法在调用用户定义的处理程序方法之前触发(即当框架知道实际参数类型时)。 如果参数类型与当前有效负载的类型不匹配,则框架会将 预配置MessageConverters查看它们中的任何一个是否可以转换有效负载。 如您所见,Object fromMessage(Message<?> message, Class<?> targetClass);MessageConverter 的作需要targetClass作为其参数之一。 该框架还确保提供的Message始终包含一个contentType页眉。 当不存在 contentType 标头时,它会注入每个绑定的contentTypeheader 或默认的contentType页眉。 的组合contentTypeArgument Type 是框架确定 message 是否可以转换为目标类型的机制。 如果没有合适的MessageConverter,则会引发异常,您可以通过添加自定义MessageConverter(参见User-defined Message Converters).spring-doc.cadn.net.cn

但是,如果有效负载类型与处理程序方法声明的目标类型匹配,该怎么办?在这种情况下,没有要转换的内容,并且 payload 的 Payload 传递时未修改。虽然这听起来非常简单且合乎逻辑,但请记住,采用Message<?>Object作为参数。 通过将目标类型声明为Object(即instanceof所有内容都在 Java 中),您基本上就放弃了转换过程。spring-doc.cadn.net.cn

不要指望Message仅根据contentType. 请记住,contentType是对 target 类型的补充。 如果您愿意,您可以提供一个提示,即MessageConverter可能会也可能不会考虑。

消息转换器

MessageConverters定义两个方法:spring-doc.cadn.net.cn

Object fromMessage(Message<?> message, Class<?> targetClass);

Message<?> toMessage(Object payload, @Nullable MessageHeaders headers);

了解这些方法的 Contract 及其用法非常重要,特别是在 Spring Cloud Stream 的上下文中。spring-doc.cadn.net.cn

fromMessage方法将传入的Message转换为参数类型。 的Message可以是任何类型,并且是 直到实际实现MessageConverter以支持多种类型。 例如,某些 JSON 转换器可能支持将有效负载类型作为byte[],String等。 当应用程序包含内部管道(即输入 → handler1 → handler2 →时,这一点非常重要。 . . .→ 输出),并且上游处理程序的输出会生成一个Message这可能不是初始连线格式。spring-doc.cadn.net.cn

但是,toMessagemethod 具有更严格的 Contract ,并且必须始终转换Message设置为连线格式:byte[].spring-doc.cadn.net.cn

因此,对于所有意图和目的(尤其是在实现您自己的转换器时),您将这两个方法视为具有以下签名:spring-doc.cadn.net.cn

Object fromMessage(Message<?> message, Class<?> targetClass);

Message<byte[]> toMessage(Object payload, @Nullable MessageHeaders headers);