Java RabbitMQ:无法将消息映射到相应的 class
Java RabbitMQ: can't map message to corresponding class
我有两个不同的 java spring 项目通过 rabbitmq 进行通信。我正在尝试发送 java object 但我收到此错误消息:
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to resolve class name. Class not found [com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO]
我知道问题出在 class 生产者和消费者中应该相同的路径,但由于每个项目都有不同的名称,我无法使 class路径相同,即使它们在相同的包中具有完全相同的 class。
class 路径存在于 header:
headers={__TypeId__=com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO}
唯一不同的是consumer app调用的是inventoryservice而不是productservice,所以总是会导致转换错误。
有什么解决方法吗?我目前的临时“解决方案”是使用原语或 java.util classes,我后来将其转换为目标 class,但它远非理想,因为我有需要发送的情况8 种不同类型的 object,我 运行 我的@RabbitHandler 的原语...
我还通过在生产者中定义目标 class 路径使其工作,但由于消息被发送到多个 queues/services,这不是一个可行的解决方案。
编辑:
这是我的配置:
活动制作人:
@Configuration
public class EventProducerConfiguration {
@Bean(name="productCreatedDeletedExchange")
public Exchange createdDeletedExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final var rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter());
return rabbitTemplate;
}
@Bean
public MessageConverter messageConverter() {
Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
DefaultClassMapper classMapper = new DefaultClassMapper();
classMapper.setTrustedPackages("*");
classMapper.setIdClassMapping(Map.of("created", ProductCreatedDTO.class));
messageConverter.setClassMapper(classMapper);
return messageConverter;
}
}
我如何发送消息:
rabbitTemplate.convertAndSend(deletedCreatedExchange.getName(), RoutingKeys.CREATED.getNotation(), new ProductCreatedDTO(p, brand.getId(), category.getId()));
事件消费者:
@Configuration
public class EventConsumerConfiguration {
@Bean(name="productsExchange")
public FanoutExchange productsPubSubExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public Queue productsQueue() {
return new Queue("productsInventoryServiceQueue");
}
@Bean
public Binding bindingProducts(@Qualifier("productsExchange") FanoutExchange productsExchange) {
return BindingBuilder
.bind(productsQueue())
.to(productsExchange);
}
@Bean
public ProductOpsReceiver productEventsReceiver() {
return new ProductOpsReceiver();
}
}
P.s.: 我不确定是否需要像在生产者配置中那样在消费者配置中使用消息转换器定义 rabbitTemaplate,但这两个应用程序都是消费者和生产者,因此仍然定义了这些 bean。
我如何接收消息:
@RabbitListener(queues="productsInventoryServiceQueue")
public class ProductOpsReceiver {
@RabbitHandler
public void productCreated(ProductCreatedDTO product) {
logger.info(PRODUCT_CREATED_LOG, product.getId());
}
}
我假设您正在使用 Jackson2JsonMessageConverter
。
您可以将类型映射添加到转换器的 typeMapper。
生产方
mapper.setIdClassMapping(Map.of(ProductCreatedDTO.class, "created"));
在消费者端将目标 class 映射到相同的令牌。
类型映射器将使用类型 ID header(在本例中为 created
)查询映射以确定要使用的类型。
我有两个不同的 java spring 项目通过 rabbitmq 进行通信。我正在尝试发送 java object 但我收到此错误消息:
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to resolve class name. Class not found [com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO]
我知道问题出在 class 生产者和消费者中应该相同的路径,但由于每个项目都有不同的名称,我无法使 class路径相同,即使它们在相同的包中具有完全相同的 class。
class 路径存在于 header:
headers={__TypeId__=com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO}
唯一不同的是consumer app调用的是inventoryservice而不是productservice,所以总是会导致转换错误。
有什么解决方法吗?我目前的临时“解决方案”是使用原语或 java.util classes,我后来将其转换为目标 class,但它远非理想,因为我有需要发送的情况8 种不同类型的 object,我 运行 我的@RabbitHandler 的原语...
我还通过在生产者中定义目标 class 路径使其工作,但由于消息被发送到多个 queues/services,这不是一个可行的解决方案。
编辑:
这是我的配置:
活动制作人:
@Configuration
public class EventProducerConfiguration {
@Bean(name="productCreatedDeletedExchange")
public Exchange createdDeletedExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final var rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter());
return rabbitTemplate;
}
@Bean
public MessageConverter messageConverter() {
Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
DefaultClassMapper classMapper = new DefaultClassMapper();
classMapper.setTrustedPackages("*");
classMapper.setIdClassMapping(Map.of("created", ProductCreatedDTO.class));
messageConverter.setClassMapper(classMapper);
return messageConverter;
}
}
我如何发送消息:
rabbitTemplate.convertAndSend(deletedCreatedExchange.getName(), RoutingKeys.CREATED.getNotation(), new ProductCreatedDTO(p, brand.getId(), category.getId()));
事件消费者:
@Configuration
public class EventConsumerConfiguration {
@Bean(name="productsExchange")
public FanoutExchange productsPubSubExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public Queue productsQueue() {
return new Queue("productsInventoryServiceQueue");
}
@Bean
public Binding bindingProducts(@Qualifier("productsExchange") FanoutExchange productsExchange) {
return BindingBuilder
.bind(productsQueue())
.to(productsExchange);
}
@Bean
public ProductOpsReceiver productEventsReceiver() {
return new ProductOpsReceiver();
}
}
P.s.: 我不确定是否需要像在生产者配置中那样在消费者配置中使用消息转换器定义 rabbitTemaplate,但这两个应用程序都是消费者和生产者,因此仍然定义了这些 bean。
我如何接收消息:
@RabbitListener(queues="productsInventoryServiceQueue")
public class ProductOpsReceiver {
@RabbitHandler
public void productCreated(ProductCreatedDTO product) {
logger.info(PRODUCT_CREATED_LOG, product.getId());
}
}
我假设您正在使用 Jackson2JsonMessageConverter
。
您可以将类型映射添加到转换器的 typeMapper。
生产方
mapper.setIdClassMapping(Map.of(ProductCreatedDTO.class, "created"));
在消费者端将目标 class 映射到相同的令牌。
类型映射器将使用类型 ID header(在本例中为 created
)查询映射以确定要使用的类型。