使用Spring缓存抽象的异步缓存更新



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

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

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

是否有可能使用Spring的缓存抽象来做这种异步缓存刷新?

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

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;
           }
         }
       });

然而,我看不到一种方法来获得refrefterwrite()的行为使用Spring的@Cacheable抽象

也许你可以尝试这样做:

  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. 读取要缓存的值假设一个字符串(我使用@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缓存抽象的项目中,我做了以下事情来达到同样的目标,但仍然隐藏了缓存的实际供应商,也就是说,它应该与Spring支持的任何缓存提供者一起工作(目前是Guava,但如果需要,应用程序可以切换到集群缓存提供者)。

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

如果我想保持代码的非侵入性,它需要使用反射和一些AOP编程来完成"捕获"部分,幸运的是,Spring AOP提供了我需要的所有工具集。

最新更新