使用Spring的缓存抽象,如何在仍然返回旧条目的同时异步刷新条目?
我正在尝试使用Spring的缓存抽象来创建一个缓存系统,在相对较短的“软”超时之后,缓存条目可以进行刷新。然后,在查询它们时,返回缓存的值,并启动异步更新操作以刷新条目。我也会
Guava的缓存构建器允许我指定缓存中的条目应在一定时间后刷新。然后可以使用异步实现覆盖缓存加载器的reload()方法,允许返回过时的缓存值,直到检索到新的缓存值。但是,spring缓存似乎不使用底层Guava缓存的CacheLoader
是否可以使用Spring的缓存抽象来进行这种异步缓存刷新?
编辑以澄清: 使用Guava的CacheBuilder,我可以使用refreshAfterWrite()来获取我想要的行为。例如来自Guava Caches Explained:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.refreshAfterWrite(1, TimeUnit.MINUTES)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) { // no checked exception
return getGraphFromDatabase(key);
}
public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
if (neverNeedsRefresh(key)) {
return Futures.immediateFuture(prevGraph);
} else {
// asynchronous!
ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
public Graph call() {
return getGraphFromDatabase(key);
}
});
executor.execute(task);
return task;
}
}
});
但是,我看不到使用Spring的@Cacheable抽象来获取refreshAfterWrite()行为的方法。
答案 0 :(得分:4)
也许你可以尝试类似的东西:
配置缓存:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
GuavaCache chache= new GuavaCache("cacheKey", CacheBuilder.newBuilder().build());
simpleCacheManager.setCaches(Arrays.asList(cacheKey));
return simpleCacheManager;
}
}
读取要缓存的值假设一个字符串(我使用@Service
作为示例)
@Service
public class MyService{
@Cacheable("cacheKey")
public String getStringCache() {
return doSomething();
}
@CachePut("cacheKey")
public String refreshStringCache() {
return doSomething();
}
...
}
getStringCache()
和refreshStringCache()
都会调用相同的函数来检索要缓存的值。 controller
只调用 getStringCache()
。
使用计划任务doc
刷新缓存@Configuration
@EnableScheduling
public class ScheduledTasks {
@Autowired
private MyService myService;
@Scheduled(fixedDelay = 30000)
public void IaaSStatusRefresh(){
myService.refreshStringCache();
}
}
通过这种方式,计划任务每30秒强制刷新一次缓存。
访问getStringCache()
的任何人都会在缓存中找到更新的数据。
答案 1 :(得分:0)
在一个使用Spring Cache抽象的项目中,我做了以下事情来达到相同的目标,但仍设法隐藏缓存的实际供应商,即它应该与Spring支持的任何缓存提供程序一起工作(目前是Guava,但应用程序如果需要,可以切换到集群缓存提供程序。)
核心概念是“捕获”缓存使用模式,并可能通过调度程序在另一个后台线程中“重放”这些操作。
如果我想保持代码非侵入性,它需要对'捕获'部分使用反射和一些AOP编程,幸运的是Spring,Spring AOP提供了我需要的所有工具集。