SpringCacheRedis 程序重启后历史缓存反序列化失败
问题描述
实体类:
@Entity
@ApiModel(value="xxxxx")
class KmlRoute : BaseModel() {
@ManyToMany(cascade = [CascadeType.REMOVE])
@JoinTable(
name = "kml_route_path",
joinColumns = [JoinColumn(name = "kml_route_id")],
inverseJoinColumns = [JoinColumn(name = "path_id")]
)
var paths: MutableList<Path>? = null
}
方法:
@Cacheable(value = ["kml"], key="#id")
fun findKmlRouteById(id: Int): KmlRoute {
logger.info("Find kmlRoute by id: {}", id)
return kmlRouteRepository.findById(id).orElse(null)
}
第一次访问findKmlRouteById方法,缓存信息到redis中,之后将程序重启,再次访问findKmlRouteById方法,KmlRoute类paths反序列化失败,报null异常(不重启就不会有问题)
问题原因
跟踪源码可得到@Cacheable 主要处理方法为 CacheAspectSupport类的execute方法
进入到findCachedItem方法中一路跟踪,可获得获取redis值的地方为RedisCache中的deserializeCacheValue方法
此处发现问题出现在序列化这里,决定替换此序列化方法,redisCache自带的方法有六种
其中GenericJackson2JsonRedisSerializer可以解决List反序列化问题,但与hibernate的懒加载存在冲突,所以此处采用fastjson替换序列化方式
解决办法
修改redis序列化方式,使用FastJson替换redis默认的JdkSerializationRedisSerializer
创建FastJsonRedisSerializer
class FastJsonRedisSerializer<T>(private val clazz: Class<T>) : RedisSerializer<T?> {
@Throws(SerializationException::class)
override fun serialize(t: T?): ByteArray? {
return if (t == null) {
ByteArray(0)
} else JSON.toJSONString(t, SerializerFeature.WriteClassName).toByteArray(DEFAULT_CHARSET)
}
@Throws(SerializationException::class)
override fun deserialize(bytes: ByteArray?): T? {
if (bytes == null || bytes.size <= 0) {
return null
}
val str = String(bytes, DEFAULT_CHARSET)
return JSON.parseObject(str, clazz) as T
}
companion object {
val DEFAULT_CHARSET = Charset.forName("UTF-8")
}
}
修改cacheManager
@Bean
fun cacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager {
val config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(FastJsonRedisSerializer(Any::class.java)))
return RedisCacheManager
.builder(redisConnectionFactory).cacheDefaults(config)
.build()
}