You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 12:17:46