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

Mechanics

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

public Function<Person, String> personFunction {..}
为了简化,我们假设这是应用程序中唯一的处理程序函数(假设内部没有流水线)。

前例中所示的处理器期望作为参数的对象,并产生字符串输入为输出。 为了让框架成功通过新来的消息作为该处理器的参数,它必须以某种方式转换消息从 wire 格式输入到类型。 换句话说,框架必须找到并应用适当的消息转换器. 为了实现这一点,框架需要用户提供一些指令。 其中一条指令已经由处理程序方法本身的签名提供(类型)。 因此,理论上,这应该(在某些情况下确实)足够。 然而,对于大多数使用场景,为了选择合适的消息转换器,框架还需要补充一条信息。 那个缺失的拼图是内容类型.spring-doc.cadn.net.cn

春云流提供了三种定义机制内容类型(按优先顺序排列):spring-doc.cadn.net.cn

  1. HEADER: the内容类型可以通过消息本身传达。通过提供一个内容类型头部时,你声明要使用的内容类型来查找并应用相应的消息转换器.spring-doc.cadn.net.cn

  2. 绑定:该内容类型可通过设置Spring.cloud.stream.bindings.input.content-type财产。spring-doc.cadn.net.cn

    输入属性名称中的 segment 对应目的地的实际名称(在我们这里是“输入”)。这种方法允许你按绑定方式声明使用的内容类型,以查找并应用合适的内容消息转换器.
  3. 默认情况下:如果内容类型不存在于消息头部或绑定,默认application/json内容类型用于 找到并应用合适的消息转换器.spring-doc.cadn.net.cn

如前所述,上述列表还展示了在出现平局时的优先顺序。例如,一个头部提供的内容类型优先于任何其他内容类型。 同样的道理也适用于针对每个绑定设置的内容类型,这本质上允许你覆盖默认内容类型。 不过,它也提供了一个合理的默认选项(这是根据社区反馈确定的)。spring-doc.cadn.net.cn

另一个原因application/json默认选择源于分布式微服务架构驱动的互作性需求,生产者和消费者不仅能运行在不同的JVM中,还能运行在不同的非JVM平台上。spring-doc.cadn.net.cn

当非空处理方法返回时,如果返回值已经是消息消息成为有效载荷。然而,当返回值不是消息,新的消息在继承时,以返回值为有效载荷构造 来自输入的头部消息减去定义或过滤的头部SpringIntegrationProperties.messageHandlerNotPropagatedHeaders. 默认情况下,那里只有一个头部:内容类型.这意味着新的消息不具备内容类型头部集合,从而确保内容类型可以进化。 你总可以选择不退货消息来自处理程序的方法,你可以注入任何你想要的头部。spring-doc.cadn.net.cn

如果存在内部管道,则消息通过相同的转换过程发送给下一个处理器。然而,如果内部没有流水线,或者你已经用到它末端,消息返回输出目的地。spring-doc.cadn.net.cn

内容类型与论元类型

如前所述,框架选择合适的消息转换器它需要参数类型,并且可选地提供内容类型信息。 选择合适 的逻辑消息转换器与论元解析器共存 (HandlerMethodArgumentResolvers),该触发点在调用用户自定义的处理程序方法之前(即框架已知实际参数类型时)。 如果参数类型与当前有效载荷的类型不匹配,框架会委派给 预配置消息转换器看看他们中是否有人能转换有效载荷。 如你所见,Object fromMessage(Message<?> message, Class<?> targetClass);MessageConverter的作目标类这是其论点之一。 该框架还确保消息总是包含一个内容类型页眉。 当没有contentType头时,它会注入以下一种绑定内容类型头部或默认内容类型页眉。 组合内容类型参数类型是框架判断消息是否可以转换为目标类型的机制。 如果不合适消息转换器如果被发现,就会抛出一个异常,你可以通过添加自定义来处理消息转换器(参见用户自定义消息转换器).spring-doc.cadn.net.cn

但如果有效载荷类型与处理方法声明的目标类型匹配呢?在这种情况下,没有什么需要转换的,且 有效载荷不加修改地通过。虽然这听起来相当简单且合乎逻辑,但请记住处理方法需要留言<?>对象作为论点。 通过声明目标类型为对象(这是一个实例Java中的一切都是这样,你基本上放弃了转换过程。spring-doc.cadn.net.cn

别抱太大期望消息仅基于内容类型. 记住内容类型与目标类型互补。 如果你愿意,可以提供一个提示,比如消息转换器可能会考虑,也可能不会。

消息转换器

消息转换器定义两种方法:spring-doc.cadn.net.cn

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

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

了解这些方法的契约及其使用方式非常重要,特别是在春云流的背景下。spring-doc.cadn.net.cn

发件消息方法转换一个输入消息变成了争吵类型。 有效载荷消息可以是任何类型,它 直到实际实现消息转换器支持多种类型。 例如,某些 JSON 转换器可能支持 的有效载荷类型为字节[],字符串,以及其他。 当应用程序包含内部流水线(即输入→处理程序1→处理程序2时,这一点尤为重要→......→输出)而上游处理器的输出则得到消息这些电缆可能不是初始的线材格式。spring-doc.cadn.net.cn

然而,收件人消息方法的约束更为严格,且必须始终转换消息转为电线格式:字节[].spring-doc.cadn.net.cn

所以,从各方面来看(尤其是在实现你自己的转换器时),你会把这两种方法视为具有以下签名:spring-doc.cadn.net.cn

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

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