使用Spring Cache Abstraction的异步缓存更新

使用Spring的缓存抽象,如何在仍然返回旧条目的同时异步刷新条目?

我正在尝试使用Spring的缓存抽象来创建一个缓存系统,在相对较短的“软”超时后,缓存条目可以进行刷新。 然后,在查询它们时,返回缓存的值,并启动异步更新操作以刷新条目。 我也会

Guava的缓存构建器允许我指定缓存中的条目应在一定时间后刷新。 然后可以使用异步实现覆盖缓存加载器的reload()方法,允许返回过时的缓存值,直到检索到新的缓存值。 但是,spring缓存似乎不使用底层Guava缓存的CacheLoader

是否可以使用Spring的缓存抽象来进行这种异步缓存刷新?

编辑澄清:使用Guava的CacheBuilder,我可以使用refreshAfterWrite()来获取我想要的行为。 例如来自Guava Caches解释 :

LoadingCache graphs = CacheBuilder.newBuilder() .maximumSize(1000) .refreshAfterWrite(1, TimeUnit.MINUTES) .build( new CacheLoader() { public Graph load(Key key) { // no checked exception return getGraphFromDatabase(key); } public ListenableFuture reload(final Key key, Graph prevGraph) { if (neverNeedsRefresh(key)) { return Futures.immediateFuture(prevGraph); } else { // asynchronous! ListenableFutureTask task = ListenableFutureTask.create(new Callable() { public Graph call() { return getGraphFromDatabase(key); } }); executor.execute(task); return task; } } }); 

但是,我看不到使用Spring的@Cacheable抽象来获取refreshAfterWrite()行为的方法。

也许你可以尝试类似的东西:

  1. 配置缓存:

     @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; } } 
  2. 读取要缓存的值假设一个String(我以@Service为例)

     @Service public class MyService{ @Cacheable("cacheKey") public String getStringCache() { return doSomething(); } @CachePut("cacheKey") public String refreshStringCache() { return doSomething(); } ... } 

    getStringCache()refreshStringCache()调用相同的函数来检索要缓存的值。 controller 调用getStringCache()

  3. 使用计划任务doc刷新缓存

     @Configuration @EnableScheduling public class ScheduledTasks { @Autowired private MyService myService; @Scheduled(fixedDelay = 30000) public void IaaSStatusRefresh(){ myService.refreshStringCache(); } } 

    通过这种方式,计划任务每​​隔30秒强制刷新一次。 访问getStringCache()任何人都会在缓存中找到更新的数据。

在一个使用Spring Cache抽象的项目中,我做了以下事情来实现相同的目标,但仍设法隐藏缓存的实际供应商,即它应该与Spring支持的任何缓存提供程序一起使用(目前是Guava,但应用程序可以切换到如果需要,则为群集缓存提供程序)。

核心概念是“捕获”缓存使用模式,并可能通过调度程序在另一个后台线程中“重放”这些操作。

如果我想保持代码非侵入性,它需要对“捕获”部分使用reflection和一些AOP编程,幸运的是,对于Spring,Spring AOP提供了我需要的所有工具集。