Fastjson2序列化器必须自定义实现RedisSerializer接口,不能直接用JSON.toJSONBytes()替代;需处理null、@type判断、类型白名单、UTF-8编码及key/value序列化分离等关键问题。

Fastjson2序列化器必须自己写,不能直接用JSON.toJSONBytes()替代RedisSerializer
Spring Boot的RedisTemplate要求值序列化器实现RedisSerializer<T>接口,而JSON.toJSONBytes()只是个静态工具方法,不处理null、字节边界、泛型类型推导等实际场景问题。直接在配置里写template.setValueSerializer(new RedisSerializer() { ... })裸实现,大概率会遇到ClassCastException或反序列化后字段为null。
正确做法是封装一个泛型类,显式持有Class<T>并控制@type写入与校验逻辑:
-
serialize()中对null返回空字节数组,避免Redis存null引发异常 - 必须启用
JSONWriter.Feature.WriteClassName,否则反序列化时无法还原具体类型 - 反序列化时不能无条件调用
JSON.parseObject(bytes, clazz)——基本类型(如Integer、String)不含@type,但JSON.parseObject强制按对象解析会失败 - 建议用
JSONReader.autoTypeFilter()白名单限制可反序列化类,防止远程代码执行(RCE)风险
FastJson2RedisSerializer要区分@type存在与否再选解析路径
fastjson2默认不写@type字段,但Redis缓存多对象类型时(比如User和Order混存),必须靠@type才能准确还原。而基本类型、字符串、Map这些天然无类型的值,如果强行加@type,反序列化会报java.lang.ClassNotFoundException或com.alibaba.fastjson2.JSONException: illegal type。
所以deserialize()里得先判断字节数组是否含@type:
- 含
@type:走带autoTypeFilter的安全解析,例如JSON.parseObject(bytes, clazz, autoTypeFilter, JSONReader.Feature.SupportClassForName) - 不含
@type:转成String后再用JSON.parseObject(str, clazz),适用于String、Long、Map等无需类型信息的场景 - 别用
new String(bytes)硬转——万一Redis里存的是二进制数据(比如图片base64),会乱码;应统一用StandardCharsets.UTF_8
RedisConfig里键必须用StringRedisSerializer,值才用Fastjson2
RedisTemplate的键(key)和值(value)序列化器要分开配,这是最容易漏的点。键必须是人类可读的字符串,比如"user:1001",如果也用Fastjson2序列化,Redis里key就变成一串JSON字节流,既没法人工查,也没法用KEYS命令匹配。
配置片段示例:
template.setKeySerializer(RedisSerializer.string()); template.setValueSerializer(new FastJson2RedisSerializer<>(Object.class));
- 别写
template.setKeySerializer(new FastJson2RedisSerializer<>(String.class))——这会让key变成"\"user:1001\"",带引号和转义 - 如果项目里key全是
String,直接用RedisSerializer.string()最稳;如果key是自定义对象(极少见),才考虑另写key序列化器 -
HashOperations、ZSetOperations等子操作器会继承RedisTemplate的序列化配置,不用单独设
升级fastjson2后旧Redis数据大概率无法直接读取
fastjson1.x和2.x序列化格式不兼容:1.x默认用SerializerFeature.WriteClassName写@type,但2.x的WriteClassName生成的@type结构不同,且默认禁用SupportClassForName。线上升级前,Redis里已有的缓存数据如果用1.x写的,2.x直接parseObject会抛JSONException: not support auto type。
稳妥方案只有两个:
- 清空Redis所有缓存(开发/测试环境可行)
- 在
deserialize()里加兼容分支:先尝试2.x解析,失败后fallback到1.x的JSON.parseObject(bytes, clazz)(需保留1.x依赖) - 千万别在生产环境边跑边改序列化器——缓存雪崩风险极高
自动类型支持白名单范围越小越安全,JSONReader.autoTypeFilter("com.example.model")比"com.example"更可控。


















