Spring AMQP 检测相似的负载类型以在@RabbitHandler 中使用

Spring AMQP detect similar payload types to use in @RabbitHandler

我曾经有一个 @RabbitListener 像这样工作得很好:

@Component
public class AppointmentMessageListener {

    @RabbitListener(queues = "${rabbitmq.immediateQueueName}")
    public void receiveImmediateAppointmentMessage(AppointmentMessage appointmentMessage) {
        // Do something
    }
}

现在我想在同一个队列上有不同类型的消息,我试过了 docs 说:

@Component
@RabbitListener(queues = "${rabbitmq.immediateQueueName}")
public class AppointmentMessageListener {

    @RabbitHandler
    public void receiveImmediateAppointmentMessage(AppointmentMessage appointmentMessage) {
        // Do something
    }

    @RabbitHandler
    public void receiveImmediateAppointmentMessage(AppointmentDeleteMessage appointmentDeleteMessage) {
        // Do something else
    }
}

这不起作用,我得到 org.springframework.amqp.AmqpException: No method found for class java.util.LinkedHashMap

JSON如下图,两者的区别仅在于object结构。我不控制消息的结构。有什么方法可以检测在我的多方法侦听器中使用的正确类型吗?

{
  "key":"event-message-resource.immediate",
  "creationTimestamp":1643804135376,
  "object": {
    // here is the object I am interested in
  }
}

除了交换、队列和路由密钥声明之外,我还使用以下配置。:

    @Bean
    public Jackson2JsonMessageConverter jsonMessageConverter() {
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
        return new Jackson2JsonMessageConverter(objectMapper);
    }

    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
                                                                               ConnectionFactory connectionFactory,
                                                                               AuthenticationRabbitListenerAdvice rabbitListenerAdvice) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        factory.setAdviceChain(combineAdvice(factory.getAdviceChain(), rabbitListenerAdvice));

        return factory;
    }

框架在使用 @RabbitHandler 时无法推断目标类型,因为它使用的是 select 方法的类型。在执行方法 selection 之前必须转换 JSON。

https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-from-message

您需要在消息中使用一些东西来确定要创建的类型。

根据受人尊敬的 Gary Russell and his answer on his post 的回答,我设法通过子类化 ClassMapper 并根据路由键决定类型来让它工作。

@Component
@RequiredArgsConstructor
public class CustomClassMapper extends DefaultJackson2JavaTypeMapper {

    @Value("${rabbitmq.deleteRoutingKey}")
    private final String deleteRoutingKey;

    @NonNull
    @Override
    public Class<?> toClass(MessageProperties properties) {
        String routingKey = properties.getReceivedRoutingKey();
        if (deleteRoutingKey.equals(routingKey)) {
            return AppointmentDeleteMessage.class;
        }

        return AppointmentMessage.class;
    }
}

然后我在messageConverter中设置了classMapper

    @Bean
    public Jackson2JsonMessageConverter jsonMessageConverter(CustomClassMapper customClassMapper) {
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
        Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(objectMapper);
        messageConverter.setClassMapper(customClassMapper);

        return messageConverter;
    }