org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Failed to convert message
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:158) ~[spring-rabbit-3.1.0.jar:3.1.0]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1662) ~[spring-rabbit-3.1.0.jar:3.1.0]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1581) ~[spring-rabbit-3.1.0.jar:3.1.0]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1569) ~[spring-rabbit-3.1.0.jar:3.1.0]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1560) ~[spring-rabbit-3.1.0.jar:3.1.0]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListenerAndHandleException(AbstractMessageListenerContainer.java:1505) ~[spring-rabbit-3.1.0.jar:3.1.0]
...
Caused by: java.lang.SecurityException: Attempt to deserialize unauthorized class com.example.springboot.dto.User; add allowed class name patterns to the message converter or, if you trust the message orginiator, set environment variable 'SPRING_AMQP_DESERIALIZATION_TRUST_ALL' or system property 'spring.amqp.deserialization.trust.all' to true
at org.springframework.amqp.utils.SerializationUtils.checkAllowedList(SerializationUtils.java:165) ~[spring-amqp-3.1.0.jar:3.1.0]
at org.springframework.amqp.support.converter.AllowedListDeserializingMessageConverter.checkAllowedList(AllowedListDeserializingMessageConverter.java:61) ~[spring-amqp-3.1.0.jar:3.1.0]
at org.springframework.amqp.support.converter.SimpleMessageConverter$1.resolveClass(SimpleMessageConverter.java:151) ~[spring-amqp-3.1.0.jar:3.1.0]
at java.base/java.io.Ob
问题与 RabbitListener 有关。请帮忙。我不知道出了什么问题。
import com.example.springboot.dto.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class RabbitMQJsonConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQJsonConsumer.class);
@RabbitListener(queues = {"${rabbitmq.queue.json.name}"})
public void consumeJsonMessage(User user){
LOGGER.info(String.format("Received JSON message -> %s", user.toString()));
}
}
当我运行应用程序时,控制台不断生成这两个异常。我正在关注 Java 指南中的本教程:https://www.youtube.com/watch?v=0--Ll3WHMTQ
不知道和配置有没有关系。我尝试在 application.properties 中将 SecurityException 中提到的那些属性设置为 true,但没有帮助。
public MessageConverter converter(){
return new Jackson2JsonMessageConverter();
}
@Bean
public AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
application.properties
既不是该例外中所述的环境,也不是系统属性。没有各自的 Spring Boot 属性。不过我们可以尝试在那里暴露它。而且它的价值有限,只有在您不提供自定义 MessageConverter
时才会应用它。
你的
rabbitTemplate.setMessageConverter(converter());
与@RabbitListener
没有任何关系。
看看您是否可以将
Jackson2JsonMessageConverter
作为 @RabbitListener
配置端的 bean 提供。
与默认的
SimpleMessageConverter
(仅适用于 Java 序列化)不同,Jackson2JsonMessageConverter
默认信任所有内容。
如果您发送 JSON,请务必考虑在消费者端也将其设为 JSON。
只是在 @ArtemBilan 评论上添加注释,这将有助于理解此错误,文档指出:
在调用监听器之前,管道中有两个转换步骤。第一个使用 MessageConverter 将传入的 Spring AMQP 消息转换为 spring-messaging 消息。当调用目标方法时,如有必要,消息负载将转换为方法参数类型。
因此传入消息的转换经历两个阶段:
a. AMQP Message -> Spring : MessageConverter (下面代码中的 simpleConverterMessage())
b. Spring -> 目标方法:方法参数转换器(下面代码中的methodMessageConverter())
@RabbitListener 使用选项 b 中的转换。文档指出: 在大多数情况下,没有必要自定义方法参数转换器,除非您想使用自定义 ConversionService。
为了解决因此引发的安全错误,我们将使用 methodMessageConverter() 自定义代码,如下所示:
@Bean("methodConverter")
public SimpleMessageConverter methodMessageConverter() {
SimpleMessageConverter converter = new SimpleMessageConverter();
converter.setAllowedListPatterns(List.of("**com.somecompany.someproject.somepackage.**"));
return converter;
}
@Bean
public MessageConverter simpleMessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(simpleMessageConverter());
rabbitTemplate.setReplyTimeout(replyTimeout);
return rabbitTemplate;
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setMessageConverter(simpleMessageConverter());
factory.setConcurrentConsumers(concurrentConsumers);
factory.setMaxConcurrentConsumers(maxConcurrentConsumers);
factory.setErrorHandler(errorHandler());
return factory;
}
然后在使用 @RabbitListener 的文件使用者中使用以下实现:
@RabbitListener(queues = {Constants.Queue_1, Constants.Queue_2}, messageConverter = "methodConverter")
public void receiveTransactionRequest(FooRequest request) {
/***your code***/
}
我不想使用环境系统或系统属性选项,原因很简单,它需要运营团队进行大量更改,从而造成不必要的负担并且容易出错。