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

Spring Boot中JMS ObjectMessage序列化异常排查与解决求助

Spring Boot JMS ObjectMessage 序列化问题排查与解决

问题描述

Spring Boot应用中使用JMS发送/接收ObjectMessage时,无法解析消息体,抛出以下异常:

jakarta.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException:

相关发送与接收代码片段:

public void send(Test test) {
    try {
        log.info("Sending Message with JMSCorrelationID: {}", test);
        ObjectMessage message = jmsTemplate.getConnectionFactory().createContext().createObjectMessage();
        message.setObject(test);
        jmsTemplate.convertAndSend(destinationName, message);
    } catch (Exception e) {
        throw new RuntimeException("Cannot send message to the Queue");
    }
}

@JmsListener(destination = "yourQueueName")
public void receiveMessage(Message message) {
    try {
        ObjectMessage objectMessage = (ObjectMessage) message;
        log.info("Received Message: " + objectMessage.getObject());
    } catch (Exception e) {
        log.error("Received Exception: " + e);
    }
}

根因分析

  • Broker类路径缺失:JMS Broker在反序列化ObjectMessage时,找不到Test类的定义。Java原生序列化要求发送方、Broker、接收方三方必须持有完全一致的序列化类(包名、类名、serialVersionUID均需匹配),若Broker类路径中无该类,就会触发ClassNotFoundException。
  • 序列化耦合性问题:Java原生序列化本身耦合性极强,类结构的微小变更(如新增字段、修改serialVersionUID)都会导致反序列化失败,且依赖类路径一致性,不适合分布式场景。
  • 代码使用错误:发送端手动创建ObjectMessage后调用convertAndSend,而jmsTemplate.convertAndSend默认会对传入对象进行转换,这会导致序列化逻辑冲突,破坏原ObjectMessage的结构。

解决方案

方案1:改用JSON序列化(推荐)

放弃Java原生序列化,使用JSON格式传递消息体,彻底摆脱类路径依赖问题:

发送端代码优化

public void send(Test test) {
    try {
        log.info("Sending Message with content: {}", test);
        // 直接发送Test对象,Spring JmsTemplate自动转为JSON格式
        jmsTemplate.convertAndSend(destinationName, test);
    } catch (Exception e) {
        throw new RuntimeException("Cannot send message to the Queue", e);
    }
}

接收端代码优化

@JmsListener(destination = "yourQueueName")
public void receiveMessage(Test test) {
    // 直接接收反序列化后的Test对象,无需手动处理Message
    log.info("Received Message: {}", test);
}

自定义JSON序列化配置(可选)

若需定制JSON规则,可在Spring配置类中添加:

@Bean
public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("_type");
    return converter;
}

方案2:修复ObjectMessage使用方式(不推荐)

若坚持使用ObjectMessage,需修正代码并保证类路径一致性:

发送端代码修正

public void send(Test test) {
    try {
        log.info("Sending Message with content: {}", test);
        // 使用send方法直接传递MessageCreator,避免重复转换
        jmsTemplate.send(destinationName, session -> {
            ObjectMessage message = session.createObjectMessage();
            message.setObject(test);
            return message;
        });
    } catch (Exception e) {
        throw new RuntimeException("Cannot send message to the Queue", e);
    }
}

类路径一致性保证

  • 确保发送端、接收端的Test类完全一致(包名、类名、serialVersionUID均相同)。
  • 将Test类所在的jar包添加到JMS Broker的类路径中(如ActiveMQ的lib目录)。

方案3:使用BytesMessage替代ObjectMessage

将对象序列化为字节数组,通过BytesMessage传递,减少Broker对业务类的依赖:

发送端

public void send(Test test) {
    try {
        log.info("Sending Message with content: {}", test);
        jmsTemplate.send(destinationName, session -> {
            BytesMessage message = session.createBytesMessage();
            // 使用ObjectOutputStream将对象转为字节数组
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            new ObjectOutputStream(bos).writeObject(test);
            message.writeBytes(bos.toByteArray());
            return message;
        });
    } catch (Exception e) {
        throw new RuntimeException("Cannot send message to the Queue", e);
    }
}

接收端

@JmsListener(destination = "yourQueueName")
public void receiveMessage(BytesMessage message) {
    try {
        byte[] bytes = new byte[(int) message.getBodyLength()];
        message.readBytes(bytes);
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        Test test = (Test) new ObjectInputStream(bis).readObject();
        log.info("Received Message: {}", test);
    } catch (Exception e) {
        log.error("Received Exception: ", e);
    }
}

此方案仍依赖Java序列化,但Broker无需持有Test类,仅需传递字节数据。

内容的提问来源于stack exchange,提问作者pppp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:52:51