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

Mechanics

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

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

前面示例中显示的处理程序需要一个对象作为参数,并生成一个类型作为输出。 为了使框架成功地将 incoming 作为参数传递给此处理程序,它必须以某种方式将类型的有效负载从 wire 格式转换为类型。 换句话说,框架必须找到并应用适当的 . 为此,框架需要用户提供一些说明。 其中一条指令已经由处理程序方法本身的签名 ( type) 提供。 因此,从理论上讲,这应该(而且在某些情况下是)足够了。 但是,对于大多数用例,为了选择合适的 ,框架需要一条额外的信息。 缺失的部分是 。PersonStringMessageMessagePersonMessageConverterPersonMessageConvertercontentTypespring-doc.cn

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

  1. HEADER:可以通过 Message 本身进行通信。通过提供标头,您可以声明用于查找和应用相应 .contentTypecontentTypeMessageConverterspring-doc.cn

  2. BINDING:可以通过设置属性来为每个目标绑定设置 。contentTypespring.cloud.stream.bindings.input.content-typespring-doc.cn

    属性名称中的区段对应于目标的实际名称(在本例中为“input”)。此方法允许您基于每个绑定声明用于查找和应用相应 .inputMessageConverter
  3. DEFAULT:如果标头或绑定中不存在 ,则默认内容类型用于 找到并应用相应的 .contentTypeMessageapplication/jsonMessageConverterspring-doc.cn

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

设为默认值的另一个原因源于分布式微服务架构驱动的互操作性需求,其中生产者和使用者不仅运行在不同的 JVM 中,而且可以在不同的非 JVM 平台上运行。application/jsonspring-doc.cn

当非 void 处理程序方法返回时,如果返回值已经是 ,则将成为有效负载。但是,当返回值不是 a 时,将在继承时使用返回值作为有效负载构造 new 标头减去定义或筛选的标头。 默认情况下,那里只有一个标头集:.这意味着 new 没有设置标头,从而确保 可以发展。 你总是可以选择不从 handler 方法返回 a,你可以在其中注入你想要的任何 header。MessageMessageMessageMessageMessageSpringIntegrationProperties.messageHandlerNotPropagatedHeaderscontentTypeMessagecontentTypecontentTypeMessagespring-doc.cn

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

内容类型与参数类型

如前所述,要使框架选择适当的 ,它需要参数类型和内容类型信息(可选)。 选择适当参数的逻辑驻留在参数解析器 () 中,该解析器在调用用户定义的处理程序方法之前触发(即当框架知道实际参数类型时)。 如果参数类型与当前有效负载的类型不匹配,则框架会将 预配置以查看它们中的任何一个是否可以转换有效负载。 如你所见,MessageConverter 的操作将作为其参数之一。 框架还确保提供的始终包含 header。 当不存在 contentType 标头时,它会注入每个绑定的标头或默认标头。 参数类型的组合是框架确定 message 是否可以转换为目标类型的机制。 如果未找到合适的,则会引发异常,您可以通过添加自定义来处理该异常(请参阅 )。MessageConverterMessageConverterHandlerMethodArgumentResolversMessageConvertersObject fromMessage(Message<?> message, Class<?> targetClass);targetClassMessagecontentTypecontentTypecontentTypecontentTypeMessageConverterMessageConverterUser-defined Message Convertersspring-doc.cn

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

不要指望仅根据 . 请记住,这是对 target type 的补充。 如果您愿意,您可以提供提示,这可能会也可能不会考虑。MessagecontentTypecontentTypeMessageConverter

消息转换器

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

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

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

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

该方法将 incoming 转换为 argument 类型。 的有效负载可以是任何类型,并且是 直到实际实现 以支持多种类型。 例如,某些 JSON 转换器可能支持有效负载类型为 、 和其他。 当应用程序包含内部管道(即输入 → handler1 → handler2 →时,这一点非常重要。 . . .→ output) 和上游处理程序的输出会导致 a 它可能不是初始 wire 格式。fromMessageMessageMessageMessageConverterbyte[]StringMessagespring-doc.cn

但是,该方法具有更严格的协定,并且必须始终转换为 wire 格式: .toMessageMessagebyte[]spring-doc.cn

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

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

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