JMS消息监听器执行失败:ClassNotFoundException问题求助
解决ActiveMQ ObjectMessage反序列化信任类问题(无法配置白名单场景)
问题背景
两个独立的Spring Boot 2.4.1应用,一个向ActiveMQ 5.18.2队列发送消息,另一个负责接收。消息可被Broker接收并被消费端获取,但消费者无法转换JMS消息,报错MyObjectMessage类不被信任、无法反序列化,且无法配置ActiveMQ白名单。
核心原因
当前使用ActiveMQObjectMessage依赖JVM原生序列化,ActiveMQ默认会校验类的信任列表,未在白名单中的类会被拦截。既然无法配置白名单,最直接的解决思路是绕开原生ObjectMessage的校验机制,改用JSON序列化方式传递消息。
解决方案:改用JSON序列化+TextMessage传递
通过Jackson将对象序列化为JSON字符串,以TextMessage形式发送;消费时再将JSON字符串反序列化为目标对象,完全避开ActiveMQ的类信任校验。
一、修改生产者配置
1. 重写MessageConverter
替换原有的FooMessageConverter,改为JSON序列化逻辑:
@Component public class FooMessageConverter implements MessageConverter { private static final Logger LOGGER = LoggerFactory.getLogger(FooMessageConverter.class); private final ObjectMapper mapper; public FooMessageConverter() { this.mapper = new ObjectMapper(); // 可根据需求添加Jackson配置,比如忽略未知字段 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } @Override public Message toMessage(Object object, Session session) throws JMSException { try { // 将对象序列化为JSON字符串 String json = mapper.writeValueAsString(object); // 创建TextMessage发送 return session.createTextMessage(json); } catch (JsonProcessingException e) { LOGGER.error("序列化对象失败", e); throw new JMSException("Failed to serialize object to JSON"); } } @Override public Object fromMessage(Message message) throws JMSException { if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { // 将JSON字符串反序列化为MyObjectMessage return mapper.readValue(textMessage.getText(), MyObjectMessage.class); } catch (JsonProcessingException e) { LOGGER.error("反序列化JSON失败", e); throw new JMSException("Failed to deserialize JSON to object"); } } return null; } }
2. 配置JmsTemplate使用自定义Converter
@Configuration public class JmsProducerConfig { @Autowired private FooMessageConverter fooMessageConverter; @Bean public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) { JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); // 绑定自定义Converter jmsTemplate.setMessageConverter(fooMessageConverter); return jmsTemplate; } }
二、修改消费者配置
1. 复用生产者的FooMessageConverter
消费者端的FooMessageConverter代码与生产者完全一致,直接复制即可。
2. 配置JmsListener容器使用自定义Converter
@Configuration @EnableJms public class JmsConsumerConfig { @Autowired private FooMessageConverter fooMessageConverter; @Bean public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); // 绑定自定义Converter factory.setMessageConverter(fooMessageConverter); return factory; } }
3. 消费者监听逻辑无需修改
原有的QueueConsumer代码保持不变,@Payload MyObjectMessage会自动通过Converter完成转换:
@Component public class QueueConsumer { private static Logger log = LoggerFactory.getLogger(QueueConsumer.class); @JmsListener(destination = "remotingQueue") public void receiveMessage(@Payload MyObjectMessage myMessage) { log.info("Q Message received: <" + myMessage + ">"); } }
三、关键注意事项
- 确保生产者和消费者的
MyObjectMessage类结构完全一致(包名、字段、序列化ID等),否则反序列化会失败。 - 彻底弃用原有的
ActiveMQObjectMessage相关代码,不再使用session.createObjectMessage方法。
内容的提问来源于stack exchange,提问作者Holland Park
相关产品推荐
相关产品推荐

