首页 文章

Spring @Cacheable:在出错时保留旧值

提问于
浏览
1

我打算使用Spring @Cacheable注释来缓存调用方法的结果 .

但是这种实现在某种程度上对我来说并不是非常“安全” . 据我所知,返回的值将由底层缓存引擎缓存,并在调用Spring evict方法时删除 .

我需要一个实现,它不会破坏旧值,直到加载新值 . 这是必需的,以下方案应该有效:

  • 调用Cacheable方法 - >返回有效结果

  • 结果将由Spring @Cacheable后端缓存

  • Spring使缓存失效,因为它已过期(例如1小时的TTL)

  • 再次调用Cacheable方法 - >返回异常/ null值!

  • OLD结果将再次缓存,因此,该方法的未来调用将返回有效结果

这怎么可能?

2 回答

  • 0

    如果@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;
            }
        }
    }
    

    CacheKey用于公开SimpleKey属性的单一目的 . Guavas refreshAfterWrite将配置刷新时间而不会使缓存条目到期 . 如果使用@Cacheable注释的方法抛出异常,则缓存将继续提供旧值,直到由于maximumSize被驱逐或被成功方法响应中的新值替换 . 您可以将refreshAfterWrite与expireAfterAccess和expireAfterAccess结合使用 .

  • 2

    我在阅读Spring代码时可能是错的,尤其是 org.springframework.cache.interceptor.CacheAspectSupport#execute(org.springframework.cache.interceptor.CacheOperationInvoker, org.springframework.cache.interceptor.CacheAspectSupport.CacheOperationContexts) ,但我相信抽象并没有提供你所要求的 .

    • Spring不会使条目到期,这将留给底层的缓存实现 .

    • 您提到即使它们已过期您也希望看到值 . 这与我所知道的大多数缓存实现中使用的到期抽象相反 .

    • 返回先前缓存的调用错误值显然是特定于用例的 . Spring抽象将简单地将错误抛回用户 . CacheErrorHandler 机制仅处理与缓存调用相关的异常 .

    总而言之,在我看来,你要求的是非常具体的用例,因此不是抽象将/应该提供的东西 .

相关问题