AMQP 消息头
概述
Spring Integration AMQP适配器会自动映射所有AMQP属性和头部信息(这是自4.3版本起的变化——此前仅映射标准头部)。默认情况下,这些属性会通过DefaultAmqpHeaderMapper在Spring Integration的MessageHeaders之间进行复制。
你可以传入自定义的 AMQP 特定头部映射器实现,因为适配器提供了支持此功能的属性。
任何用户自定义的头部信息,只要位于 AMQP MessageProperties 中,都会被复制到 AMQP 消息中或从 AMQP 消息中复制出来,除非被 DefaultAmqpHeaderMapper 的 requestHeaderNames 或 replyHeaderNames 属性明确排除。默认情况下,对于出站映射器,不会映射任何 x-* 头部。关于原因,请参阅本节稍后出现的注意事项。
要覆盖默认设置并恢复至 4.3 版本之前的行为,请在属性中使用 STANDARD_REQUEST_HEADERS 和 STANDARD_REPLY_HEADERS。
在映射用户自定义头部时,值也可以包含简单的通配符模式(例如 thing* 或 *thing)进行匹配。* 匹配所有头部。
从 4.1 版本开始,AbstractHeaderMapper(DefaultAmqpHeaderMapper 的超类)允许为 requestHeaderNames 和 replyHeaderNames 属性配置 NON_STANDARD_HEADERS 标记(除了现有的 STANDARD_REQUEST_HEADERS 和 STANDARD_REPLY_HEADERS),以映射所有用户自定义的头部。
org.springframework.amqp.support.AmqpHeaders 类标识了 DefaultAmqpHeaderMapper 所使用的默认头部信息:
-
amqp_appId -
amqp_clusterId -
amqp_contentEncoding -
amqp_contentLength -
content-type(参见 The contentType Header) -
amqp_correlationId -
amqp_delay -
amqp_deliveryMode -
amqp_deliveryTag -
amqp_expiration -
amqp_messageCount -
amqp_messageId -
amqp_receivedDelay -
amqp_receivedDeliveryMode -
amqp_receivedExchange -
amqp_receivedRoutingKey -
amqp_redelivered -
amqp_replyTo -
amqp_timestamp -
amqp_type -
amqp_userId -
amqp_publishConfirm -
amqp_publishConfirmNackCause -
amqp_returnReplyCode -
amqp_returnReplyText -
amqp_returnExchange -
amqp_returnRoutingKey -
amqp_channel -
amqp_consumerTag -
amqp_consumerQueue
正如本节前面提到的,使用 * 作为头部映射模式是一种复制所有头部的常见方式。然而,这可能会产生一些意想不到的副作用,因为某些 RabbitMQ 专有属性/头部也会被复制。例如,当你使用联邦时,接收到的消息可能有一个名为 x-received-from 的属性,其中包含发送消息的节点。如果你在入站网关上对请求和回复头部映射使用通配符 *,这个头部会被复制,这可能会导致联邦功能出现一些问题。此回复消息可能会被联邦回发送代理,而发送代理可能认为消息在循环,因此会静默丢弃它。如果你希望使用通配符头部映射的便利性,可能需要在下游流程中过滤掉一些头部。例如,为了避免将 x-received-from 头部复制回回复,你可以在将回复发送到 AMQP 入站网关之前使用 <int:header-filter … header-names="x-received-from">。或者,你可以明确列出你实际想要映射的那些属性,而不是使用通配符。由于这些原因,对于入站消息,映射器(默认情况下)不会映射任何 x-* 头部。它也不会将 deliveryMode 映射到 amqp_deliveryMode 头部,以避免该头部从入站消息传播到出站消息。相反,该头部被映射到 amqp_receivedDeliveryMode,而后者在输出时不会被映射。
从版本 4.3 开始,可以通过在模式前添加 ! 来对头部映射中的模式进行取反。取反模式具有优先级,因此像 STANDARD_REQUEST_HEADERS,thing1,ba*,!thing2,!thing3,qux,!thing1 这样的列表不会映射 thing1(也不会映射 thing2 和 thing3)。标准头部加上 bad 和 qux 会被映射。取反技术在某些场景下很有用,例如,当接收端下游以不同方式处理 JSON 反序列化逻辑时,可以避免映射传入消息的 JSON 类型头部。为此,可以在入站通道适配器/网关的头部映射器中配置 !json_* 模式。
如果你有一个以 ! 开头的自定义请求头,并且你希望映射它,你需要使用 \ 进行转义,如下所示:STANDARD_REQUEST_HEADERS,\!myBangHeader。这样,名为 !myBangHeader 的请求头就会被映射。
从版本 5.1 开始,如果出站消息上不存在相应的 amqp_messageId 或 amqp_timestamp 头部,DefaultAmqpHeaderMapper 将回退到分别将 MessageHeaders.ID 和 MessageHeaders.TIMESTAMP 映射到 MessageProperties.messageId 和 MessageProperties.timestamp。入站属性将像以前一样映射到 amqp_* 头部。当消息消费者使用有状态重试时,填充 messageId 属性非常有用。
contentType 头部
与其他头部不同,AmqpHeaders.CONTENT_TYPE 没有以 amqp_ 作为前缀;这允许跨不同技术透明地传递 contentType 头部。例如,发送到 RabbitMQ 队列的入站 HTTP 消息。
contentType 头部被映射到 Spring AMQP 的 MessageProperties.contentType 属性,随后该属性又被映射到 RabbitMQ 的 content_type 属性。
在5.1版本之前,此头部也被映射为 MessageProperties.headers 映射中的一个条目;这是不正确的,而且由于底层的Spring AMQP消息转换器可能更改了内容类型,该值也可能是错误的。此类更改会反映在一级属性 content_type 中,但不会反映在RabbitMQ头部映射中。入站映射会忽略头部映射中的值。contentType 不再被映射到头部映射的条目中。