AMQP Message Headers

Overview

Spring Integration AMQP 适配器自动映射所有 AMQP 属性和标头。(这是 4.3 版的一个更改 - 以前仅映射标准标头)。默认情况下,这些属性使用 DefaultAmqpHeaderMapper 复制到 Spring Integration MessageHeaders 和从 Spring Integration MessageHeaders 复制到 Spring Integration MessageHeaders

The Spring Integration AMQP Adapters automatically map all AMQP properties and headers. (This is a change from 4.3 - previously, only standard headers were mapped). By default, these properties are copied to and from Spring Integration MessageHeaders by using the DefaultAmqpHeaderMapper.

可以传入 AMQP 特定标头映射器的自定义实现,因为适配器具有支持此操作的属性。

You can pass in your own implementation of AMQP-specific header mappers, as the adapters have properties to support doing so.

AMQP MessageProperties 中的所有用户定义头都会被复制到 AMQP 消息中或从 AMQP 消息中复制,除非 DefaultAmqpHeaderMapperrequestHeaderNamesreplyHeaderNames 属性明确地否定了它们。默认情况下,对于出站映射器,没有一个 x-* 头被映射。有关原因,请参阅稍后在本章节中出现的 caution

Any user-defined headers within the AMQP MessageProperties are copied to or from an AMQP message, unless explicitly negated by the requestHeaderNames or replyHeaderNames properties of the DefaultAmqpHeaderMapper. By default, for an outbound mapper, no x-* headers are mapped. See the caution that appears later in this section for why.

若要覆盖默认设置并恢复到 4.3 之前的行为,请在属性中使用 STANDARD_REQUEST_HEADERSSTANDARD_REPLY_HEADERS

To override the default and revert to the pre-4.3 behavior, use STANDARD_REQUEST_HEADERS and STANDARD_REPLY_HEADERS in the properties.

映射用户定义的头时,值还可以包含简单的通配符模式(例如,thing*thing) to be matched. The 匹配所有标头)。

When mapping user-defined headers, the values can also contain simple wildcard patterns (such as thing* or thing) to be matched. The matches all headers.

从 4.1 版开始,AbstractHeaderMapperDefaultAmqpHeaderMapper 超类)允许为 requestHeaderNamesreplyHeaderNames 属性(除现有的 STANDARD_REQUEST_HEADERSSTANDARD_REPLY_HEADERS 外)配置 `NON_STANDARD_HEADERS`令牌,以映射所有用户定义的标头。

Starting with version 4.1, the AbstractHeaderMapper (a DefaultAmqpHeaderMapper superclass) lets the NON_STANDARD_HEADERS token be configured for the requestHeaderNames and replyHeaderNames properties (in addition to the existing STANDARD_REQUEST_HEADERS and STANDARD_REPLY_HEADERS) to map all user-defined headers.

org.springframework.amqp.support.AmqpHeaders 类标识由 DefaultAmqpHeaderMapper 使用的默认标头:

The org.springframework.amqp.support.AmqpHeaders class identifies the default headers that are used by the DefaultAmqpHeaderMapper:

  • amqp_appId

  • amqp_clusterId

  • amqp_contentEncoding

  • amqp_contentLength

  • content-type (see 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

正如本节前面提到的,对入站网关的请求和答复标头映射使用 is a common way to copy all headers. However, this can have some unexpected side effects, because certain RabbitMQ proprietary properties/headers are also copied. For example, when you use federation, the received message may have a property named x-received-from, which contains the node that sent the message. If you use the wildcard character 的标头映射模式,此标头会被复制,这可能会导致联合的一些问题。此答复报文可能会联合回发送代理程序,而代理程序可能认为报文正在循环并且因此静默地丢弃它。如果您希望使用通配符标头映射的便利性,您可能需要在下游流中过滤掉一些标头。例如,要避免将 x-received-from 标头复制回答复,您可以在将答复发送到 AMQP 入站网关之前使用 <int:header-filter …​ header-names="x-received-from">。或者,您可以显式列出您实际想要映射的那些属性,而不是使用通配符。由于这些原因,对于入站报文,映射器(默认情况下)不会映射任何 x-* 标头。它也不会将 deliveryMode 映射到 amqp_deliveryMode 标头,以避免该标头从入站报文传播到出站报文。相反,此标头映射到 amqp_receivedDeliveryMode,而 amqp_receivedDeliveryMode 在输出时不会被映射。

As mentioned earlier in this section, using a header mapping pattern of is a common way to copy all headers. However, this can have some unexpected side effects, because certain RabbitMQ proprietary properties/headers are also copied. For example, when you use federation, the received message may have a property named x-received-from, which contains the node that sent the message. If you use the wildcard character for the request and reply header mapping on the inbound gateway, this header is copied, which may cause some issues with federation. This reply message may be federated back to the sending broker, which may think that a message is looping and, as a result, silently drop it. If you wish to use the convenience of wildcard header mapping, you may need to filter out some headers in the downstream flow. For example, to avoid copying the x-received-from header back to the reply you can use <int:header-filter …​ header-names="x-received-from"> before sending the reply to the AMQP inbound gateway. Alternatively, you can explicitly list those properties that you actually want mapped, instead of using wildcards. For these reasons, for inbound messages, the mapper (by default) does not map any x-* headers. It also does not map the deliveryMode to the amqp_deliveryMode header, to avoid propagation of that header from an inbound message to an outbound message. Instead, this header is mapped to amqp_receivedDeliveryMode, which is not mapped on output.

从 4.3 版开始,可以在标头映射中使用 ! 否定模式,方法是在模式前加 !。否定模式具有优先级,所以诸如 STANDARD_REQUEST_HEADERS,thing1,ba*,!thing2,!thing3,qux,!thing1 的列表不会映射 thing1(也不会映射 thing2thing3)。将映射标准标头加上 badqux。否定技术可能很有用,例如在接收器在不同下游采用 JSON 反序列化逻辑时,不为传入消息映射 JSON 类型标头。为此目的,应为入站通道适配器/网关的标头映射器配置 !json_* 模式。

Starting with version 4.3, patterns in the header mappings can be negated by preceding the pattern with !. Negated patterns get priority, so a list such as STANDARD_REQUEST_HEADERS,thing1,ba*,!thing2,!thing3,qux,!thing1 does not map thing1 (nor thing2 nor thing3). The standard headers plus bad and qux are mapped. The negation technique can be useful for example to not map JSON type headers for incoming messages when a JSON deserialization logic is done in the receiver downstream different way. For this purpose a !json_* pattern should be configured for header mapper of the inbound channel adapter/gateway.

如果你有一个以 ! 开头的用户自定义标头,并且希望映射它,你需要使用 \ 对其进行转义,如下所示:STANDARD_REQUEST_HEADERS,\!myBangHeader。名为 !myBangHeader 的标头现在已映射。

If you have a user-defined header that begins with ! that you do wish to map, you need to escape it with \, as follows: STANDARD_REQUEST_HEADERS,\!myBangHeader. The header named !myBangHeader is now mapped.

从版本 5.1 开始,如果出站消息中不存在对应的 amqp_messageIdamqp_timestamp 标头,DefaultAmqpHeaderMapper 将回退为将 MessageHeaders.IDMessageHeaders.TIMESTAMP 分别映射到 MessageProperties.messageIdMessageProperties.timestamp。入站属性将像以前一样映射到 amqp_* 标头。当消息使用者使用有状态重试时,填充 messageId 属性很有用。

Starting with version 5.1, the DefaultAmqpHeaderMapper will fall back to mapping MessageHeaders.ID and MessageHeaders.TIMESTAMP to MessageProperties.messageId and MessageProperties.timestamp respectively, if the corresponding amqp_messageId or amqp_timestamp headers are not present on outbound messages. Inbound properties will be mapped to the amqp_* headers as before. It is useful to populate the messageId property when message consumers are using stateful retry.

The contentType Header

与其他标头不同,AmqpHeaders.CONTENT_TYPE 不带 amqp_ 前缀;这允许跨不同技术透明地传递 contentType 标头。例如,发送到 RabbitMQ 队列的入站 HTTP 消息。

Unlike other headers, the AmqpHeaders.CONTENT_TYPE is not prefixed with amqp_; this allows transparent passing of the contentType header across different technologies. For example an inbound HTTP message sent to a RabbitMQ queue.

contentType 标头映射到 Spring AMQP 的 MessageProperties.contentType 属性,然后映射到 RabbitMQ 的 content_type 属性。

The contentType header is mapped to Spring AMQP’s MessageProperties.contentType property and that is subsequently mapped to RabbitMQ’s content_type property.

在版本 5.1 之前,此标头也映射为 MessageProperties.headers 映射中的一个条目;这是不正确的,并且,此外,值可能是错误的,因为基础 Spring AMQP 消息转换器可能已更改了内容类型。此类更改将反映在一流的 content_type 属性中,但不会反映在 RabbitMQ 标头映射中。入站映射忽略标头映射值。contentType 不再映射为标头映射中的一个条目。

Prior to version 5.1, this header was also mapped as an entry in the MessageProperties.headers map; this was incorrect and, furthermore, the value could be wrong since the underlying Spring AMQP message converter might have changed the content type. Such a change would be reflected in the first-class content_type property, but not in the RabbitMQ headers map. Inbound mapping ignored the headers map value. contentType is no longer mapped to an entry in the headers map.