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。
您需要在消息中使用一些东西来确定要创建的类型。
根据受人尊敬的 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;
}
我曾经有一个 @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。
您需要在消息中使用一些东西来确定要创建的类型。
根据受人尊敬的 Gary Russell and his answer on his post
@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;
}