如何强制Spring Cache调用带返回类型参数的get方法?
get(Object key, Class<T> type)方法 要解决Spring调用无类型get方法导致无法获取反序列化目标类型的问题,你需要调整Cache实现的逻辑,引导Spring优先调用带类型参数的get方法,具体步骤如下:
1. 修正无类型get方法的实现
Spring Cache切面在获取缓存时,会先尝试调用无参数类型的get(Object key)方法。如果该方法返回非null的ValueWrapper,Spring就会直接使用这个值,不会再调用带类型参数的重载方法。
因此,你需要修改SqlCache中的get(key: Any)方法,不要在该方法中硬编码反序列化类型(比如你当前写死的UserModel),而是让它返回null,迫使Spring转而调用带类型参数的get方法:
override fun get(key: Any): Cache.ValueWrapper? { // 无类型信息时无法正确反序列化,返回null让Spring调用带类型的方法 return null }
如果想明确禁止无类型get方法的调用(避免误用),也可以抛出异常:
override fun get(key: Any): Cache.ValueWrapper? { throw UnsupportedOperationException("该缓存需要类型信息才能反序列化,请使用带类型参数的get方法") }
2. 确保带类型参数的get方法正确处理反序列化
你的get(key: Any, type: Class<T>?)方法已经实现了基于传入类型的反序列化逻辑,只需确保type参数不为空即可(Spring在调用该方法时,会自动传入目标方法的返回类型,比如UserModel::class.java):
override fun <T : Any?> get(key: Any, type: Class<T>?): T? { requireNotNull(type) { "反序列化需要指定目标类型" } val cache = cacheRepository.find(name = name, key = key.toString()) ?: return null return isoObjectMapper.readValue(cache.value, type) }
3. 修正put方法的序列化逻辑
确保存储到数据库的是JSON字符串,而不是对象本身(避免cacheRepository处理序列化时出现不一致):
override fun put(key: Any, value: Any?) { val jsonValue = value?.let { isoObjectMapper.writeValueAsString(it) } cacheRepository.put( name = name, key = key.toString(), value = jsonValue, expiration = expiration, ) }
原理说明
当你使用@Cacheable注解时,Spring Cache切面会解析目标方法的返回类型(比如getUser方法的UserModel)。如果无类型get方法返回null,Spring会自动调用带类型参数的get(key, requiredType)方法,将目标方法的返回类型传入,这样你就能在缓存实现中基于该类型完成JSON反序列化。
内容的提问来源于stack exchange,提问作者Oreste Viron

