如何更改消息类型检测策略?

How to change message type detection strategy?

我在应用程序 A 中使用自定义 RabbitMQ 客户端,在应用程序 B 中使用 Spring Amqp Library。 我遇到了一个问题:如何决定 @RabbitListener 用于不同的消息类型?

问题: 我从应用程序 A 向应用程序 B 发送自定义消息。在一条消息中,我设置了自定义 header “类型” - 它不是默认值 属性 也不是默认值 Spring Amqp Header (这是“_ _ TypeId _ _”)——只是一个新的自定义 header。

在应用程序 B (spring amqp) 中,我必须决定使用哪个侦听器。据我了解,Spring Amqp 使用“_ _ TypeId _ _”作为“消息类型检测策略”的默认机制(我不知道如何正确调用它),但我想使用我自己的“策略” ”.

我找到了下一个技巧,但它看起来很奇怪而且不明显:

private void determineMessageType(Message message) {
    MessageProperties props = message.getMessageProperties();
    Map<String, Object> headers = props.getHeaders();
    final String type = String.valueOf(headers.get("type"));
    if ("popularity-report".equals(type)) {
        props.getHeaders().put("__TypeId__",
                PopularityReportCommand.class.getName());
    } 
}

我可以为 Spring Amqp 应用程序使用自定义类型检测策略吗?或者如何在 Spring Amqp 中正确解决这些问题?

提到的 _ _ TypeId _ _ 仅用于 JSON 消息转换器。因此,如果在您真正从该制作人发送的部分中确实是您的情况,那么您可以查看 AbstractJackson2MessageConverter.setJavaTypeMapper(Jackson2JavaTypeMapper)。默认的 DefaultJackson2JavaTypeMapper 有一个 属性 像这样:

public String getClassIdFieldName() {
    return DEFAULT_CLASSID_FIELD_NAME;
}

这就是上面提到的名字:

public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__";

因此,如果您能够扩展此 DefaultJackson2JavaTypeMapper 并为您的自定义 header 映射器覆盖 getter,那么 Jackson2JsonMessageConverter 可以正确转换传入 JSON 数据转换为您的自定义 header 呈现的所需类型。然后 @RabbitListener 将接受该值。

但您仍然需要确保该映射器上的 typePrecedence 设置为 TYPE_ID:

/**
 * Set the precedence for evaluating type information in message properties.
 * When using {@code @RabbitListener} at the method level, the framework attempts
 * to determine the target type for payload conversion from the method signature.
 * If so, this type is provided in the
 * {@link MessageProperties#getInferredArgumentType() inferredArgumentType}
 * message property.
 * <p>
 * By default, if the type is concrete (not abstract, not an interface), this will
 * be used ahead of type information provided in the {@code __TypeId__} and
 * associated headers provided by the sender.
 * <p>
 * If you wish to force the use of the  {@code __TypeId__} and associated headers
 * (such as when the actual type is a subclass of the method argument type),
 * set the precedence to {@link Jackson2JavaTypeMapper.TypePrecedence#TYPE_ID}.
 *
 * @param typePrecedence the precedence.
 * @since 1.6
 */
public void setTypePrecedence(TypePrecedence typePrecedence) {

否则它会参考 @RabbitListener 方法签名。

在文档中查看更多信息:https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-from-message