Java Spring@Cacheable:错误时保留旧值
我计划使用Spring@Cacheable注释来缓存调用方法的结果 但是这个实现在我看来并不十分“安全”。据我所知,返回的值将由底层缓存引擎缓存,并在调用Spring execute方法时删除 我需要一个在加载新值之前不会破坏旧值的实现。这是必需的,以下场景应该可以工作:Java Spring@Cacheable:错误时保留旧值,java,spring,caching,guava,ehcache,Java,Spring,Caching,Guava,Ehcache,我计划使用Spring@Cacheable注释来缓存调用方法的结果 但是这个实现在我看来并不十分“安全”。据我所知,返回的值将由底层缓存引擎缓存,并在调用Spring execute方法时删除 我需要一个在加载新值之前不会破坏旧值的实现。这是必需的,以下场景应该可以工作: 调用可缓存方法->返回有效结果 结果将由Spring@Cacheable后端缓存 Spring使缓存失效,因为它已过期(例如,TTL为1小时) 再次调用可缓存方法->返回异常/空值 旧结果将再次缓存,因此,该方法的未来调用将返
这怎么可能呢?我对Spring代码的理解可能是错误的,尤其是
org.springframework.cache.interceptor.CacheAspectSupport#执行(org.springframework.cache.interceptor.CacheAspectSupport.cacheOperationContext,org.springframework.cache.interceptor.CacheAspectSupport.cacheOperationContext)
,但我相信抽象并不能提供你真正需要的东西
CacheErrorHandler
机制只处理与缓存调用相关的异常总而言之,在我看来,您所要求的是非常特定于用例的,因此不是抽象会/应该提供的东西。如果
@Cacheable
方法抛出异常,您服务旧值的要求可以通过对Google Guava的最小扩展轻松实现
使用以下配置示例
@Configuration
@EnableWebMvc
@EnableCaching
@ComponentScan("com.yonosoft.poc.cache")
public class ApplicationConfig extends CachingConfigurerSupport {
@Bean
@Override
public CacheManager cacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
GuavaCache todoCache = new GuavaCache("todo", CacheBuilder.newBuilder()
.refreshAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(10)
.build(new CacheLoader<Object, Object>() {
@Override
public Object load(Object key) throws Exception {
CacheKey cacheKey = (CacheKey)key;
return cacheKey.method.invoke(cacheKey.target, cacheKey.params);
}
}));
simpleCacheManager.setCaches(Arrays.asList(todoCache));
return simpleCacheManager;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
return new CacheKey(target, method, params);
}
};
}
private class CacheKey extends SimpleKey {
private static final long serialVersionUID = -1013132832917334168L;
private Object target;
private Method method;
private Object[] params;
private CacheKey(Object target, Method method, Object... params) {
super(params);
this.target = target;
this.method = method;
this.params = params;
}
}
}
@配置
@EnableWebMvc
@启用缓存
@组件扫描(“com.yonosoft.poc.cache”)
公共类应用程序配置扩展了CachingConfigurerSupport{
@豆子
@凌驾
公共缓存管理器缓存管理器(){
SimpleCacheManager SimpleCacheManager=新SimpleCacheManager();
GuavaCache-todoCache=新的GuavaCache(“todo”,CacheBuilder.newBuilder()
.refreshAfterWrite(10,时间单位:分钟)
.最大尺寸(10)
.build(新的缓存加载程序(){
@凌驾
公共对象加载(对象键)引发异常{
CacheKey CacheKey=(CacheKey)key;
返回cacheKey.method.invoke(cacheKey.target,cacheKey.params);
}
}));
setCaches(Arrays.asList(todoCache));
返回simpleCacheManager;
}
@豆子
@凌驾
公钥生成器KeyGenerator(){
返回新的KeyGenerator(){
@凌驾
公共对象生成(对象目标、方法、对象…参数){
返回新的CacheKey(目标、方法、参数);
}
};
}
私有类CacheKey扩展了SimpleKey{
私有静态最终长SerialVersionId=-1013132832917334168L;
私有对象目标;
私有方法;
私有对象[]参数;
专用缓存密钥(对象目标、方法、对象…参数){
超级(params);
this.target=目标;
这个方法=方法;
this.params=params;
}
}
}
CacheKey
仅用于公开SimpleKey
属性。Guavas refreshAfterWrite将配置刷新时间,而不会使缓存项过期。如果用@Cacheable
注释的方法抛出异常,则缓存将继续服务于旧值,直到由于maximumSize
而被逐出,或者被成功方法响应中的新值替换。您可以将refreshAfterWrite
与expireAfterAccess
和expireAfterAccess
结合使用