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

如何在Spring框架外反序列化Redis中存储的Java对象

解决Spring Session Redis二进制数据反序列化问题

你遇到的StreamCorruptedException核心原因确实是把Redis中存储的JDK序列化二进制数据当成UTF-8字符串处理,导致字节丢失或损坏。从你给出的Redis字符串开头\xAC\xED\x00\x05就能看出来,这是JDK序列化的标志性魔数,这类二进制数据根本不能直接转成String再转回byte[]——UTF-8是字符编码,不是二进制容器,很多无效的字节序列会被替换成�(也就是错误信息里的EFBFBDEF,这是UTF-8替换字符的字节码),直接导致反序列化失败。

无需修改序列化逻辑的解决方案

你完全不需要改动Spring端的序列化配置,只需要在Jedis操作时跳过String转换,直接读取原始二进制数据即可。Jedis提供了完整的二进制API,对应字符串操作的二进制版本,比如hGetAll(byte[] key)代替hgetAll(String key),这样就能拿到完整的序列化字节数组,直接反序列化就没问题了。

修改后的代码示例

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.Jedis;

private static void scanKeys(Jedis jedis, String prefix, String hashKey) throws IOException, ClassNotFoundException {
    // 将前缀转换为字节数组(Redis默认用UTF-8编码键)
    byte[] prefixBytes = prefix.getBytes(StandardCharsets.UTF_8);
    byte[] patternBytes = Arrays.copyOf(prefixBytes, prefixBytes.length + 1);
    patternBytes[prefixBytes.length] = '*'; // 拼接通配符
    
    Set<byte[]> keys = jedis.keys(patternBytes);
    
    for (byte[] key : keys) {
        String keyStr = new String(key, StandardCharsets.UTF_8);
        if (!keyStr.contains("expir")) {
            // 使用二进制API获取哈希表的所有键值对
            Map<byte[], byte[]> sessionMap = jedis.hGetAll(key);
            byte[] targetHashKeyBytes = hashKey.getBytes(StandardCharsets.UTF_8);
            
            for (Map.Entry<byte[], byte[]> entry : sessionMap.entrySet()) {
                if (Arrays.equals(entry.getKey(), targetHashKeyBytes) && entry.getValue() != null) {
                    String hashKeyStr = new String(entry.getKey(), StandardCharsets.UTF_8);
                    System.out.println(hashKeyStr);
                    
                    // 直接使用原始字节数组反序列化
                    try {
                        Long id = (Long) deserialize(entry.getValue());
                        System.out.println(id);
                    } catch (EOFException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
        }
    }
}

public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
    // 使用try-with-resources自动关闭流
    try (ByteArrayInputStream in = new ByteArrayInputStream(data);
         ObjectInputStream is = new ObjectInputStream(in)) {
        return is.readObject();
    }
}

关键改动说明

  • 所有Redis键相关操作改用二进制API:keys(byte[])、hGetAll(byte[]),彻底避免字符串转换带来的字节损坏
  • 仅在需要打印或判断键的字符串内容时,才将字节数组转为String(确保用UTF-8编码,和Redis的键编码一致)
  • 直接使用从Redis获取的原始byte[]进行反序列化,完整保留JDK序列化的原始二进制数据

这样就能在不修改Spring Session序列化配置的前提下,正确反序列化出Java对象了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:33:03