我打算使用Spring @Cacheable批注来缓存调用方法的结果。
但是这种实现对我而言似乎并不十分“安全”。据我了解,返回值将由基础缓存引擎缓存,并在调用Spring evict方法时将其删除。
我需要一个在加载新值之前不破坏旧值的实现。这将是必需的,并且以下情况应该起作用:
这怎么可能?
如果您仅需对Google Guava进行最小扩展,就可以轻松实现您对@Cacheable
方法引发异常时提供旧值的要求。
使用以下示例配置
@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;
}
}
}
CacheKey
仅用于公开SimpleKey
属性。 Guavas refreshAfterWrite将配置刷新时间,而不会使缓存条目到期。如果用@Cacheable
注释的方法引发异常,则高速缓存将继续提供旧值,直到由于maximumSize
被逐出为止或被成功的方法响应替换为新值。您可以将refreshAfterWrite
与expireAfterAccess
和expireAfterAccess
结合使用。
我在阅读Spring代码时可能错了,特别是org.springframework.cache.interceptor.CacheAspectSupport#execute(org.springframework.cache.interceptor.CacheOperationInvoker, org.springframework.cache.interceptor.CacheAspectSupport.CacheOperationContexts)
,但我相信抽象并不能提供您确实提出的要求。
CacheErrorHandler
机制仅处理与缓存调用相关的异常。总而言之,在我看来,您所要求的是非常特定于用例的,因此不是抽象将/不应该提供的。