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

Redis存储对象类名变更后反序列化失败的解决方案问询

解决Redis反序列化类名变更后的SerializationException问题

这个问题我之前也碰到过,核心原因是Redis默认使用的JDK序列化机制,会把类的全限定名硬编码在序列化的字节数据里。你把类名从StorageConnection改成DataConnection后,反序列化时JVM找不到旧类名对应的类,自然就抛出SerializationException了。好在你说字段和serialVersionUID都没变,有两个靠谱的解决技巧:

技巧1:自定义序列化器,映射新旧类名

通过重写JDK序列化器的类解析逻辑,把旧类名替换成新类名,这样就能兼容旧数据的反序列化了。

先写一个自定义的序列化器:

import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

public class CustomJdkSerializer extends JdkSerializationRedisSerializer {
    @Override
    protected Object deserialize(byte[] bytes) {
        try (ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
             ObjectInputStream objectStream = new ObjectInputStream(byteStream) {
                 @Override
                 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                     // 把旧类名替换成新类名,注意替换成你实际的包路径
                     if ("com.yourpackage.StorageConnection".equals(desc.getName())) {
                         return DataConnection.class;
                     }
                     return super.resolveClass(desc);
                 }
             }) {
            return objectStream.readObject();
        } catch (Exception ex) {
            throw new SerializationException("Could not deserialize object", ex);
        }
    }
}

然后把这个序列化器配置到你的RedisTemplate里:

// 在AdminDataBaseServiceImpl的构造方法或者配置类中设置
this.redisTemplateAdmin.setValueSerializer(new CustomJdkSerializer());
this.redisTemplateAdmin.setHashValueSerializer(new CustomJdkSerializer());
this.redisTemplateAdmin.afterPropertiesSet();

这样修改后,不管是旧数据还是新存的数据,都能正常反序列化成DataConnection对象。

技巧2:一次性迁移旧数据

如果你的Redis数据量不大,或者不需要长期兼容旧类名,可以一次性把旧数据读取出来,转换成新类再存回去。

写一段临时执行的迁移代码:

import org.springframework.beans.BeanUtils;

// 注意:这段代码只需要执行一次,完成后就可以删掉
public void migrateOldData(String uniqueKey) {
    // 先用旧类读取数据
    StorageConnection oldConn = (StorageConnection) redisTemplateAdmin.opsForValue().get(uniqueKey);
    if (oldConn != null) {
        // 转换成新类,因为字段完全一致,可以用BeanUtils拷贝
        DataConnection newConn = new DataConnection();
        BeanUtils.copyProperties(oldConn, newConn);
        // 重新存入Redis
        redisTemplateAdmin.opsForValue().set(uniqueKey, newConn);
    }
}

执行完这段代码后,所有旧数据都会被替换成新类的序列化数据,之后就可以用正常的反序列化逻辑了。

重要提醒

一定要确保StorageConnection和DataConnection的serialVersionUID完全相同,你已经提到UID保持不变,这点刚好满足,不然即使字段一样,也会因为UID不匹配抛出序列化异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:22:53