Spring @Cacheable:保留错误时的旧值

问题描述 投票:3回答:2

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

但是这种实现对我而言似乎并不十分“安全”。据我了解,返回值将由基础缓存引擎缓存,并在调用Spring evict方法时将其删除。

我需要一个在加载新值之前不破坏旧值的实现。这将是必需的,并且以下情况应该起作用:

  1. 调用可缓存方法->返回有效结果
  2. 结果将由Spring @Cacheable后端缓存
  3. Spring使缓存失效,因为它已过期(例如TTL为1小时)
  4. 再次调用可缓存方法->返回异常/空值!
  5. OLD结果将再次被缓存,因此,将来对该方法的调用将返回有效结果

这怎么可能?

java spring caching guava ehcache
2个回答
2
投票

如果您仅需对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被逐出为止或被成功的方法响应替换为新值。您可以将refreshAfterWriteexpireAfterAccessexpireAfterAccess结合使用。


0
投票

我在阅读Spring代码时可能错了,特别是org.springframework.cache.interceptor.CacheAspectSupport#execute(org.springframework.cache.interceptor.CacheOperationInvoker, org.springframework.cache.interceptor.CacheAspectSupport.CacheOperationContexts),但我相信抽象并不能提供您确实提出的要求。

  1. Spring不会使条目过期,这将留给底层的缓存实现。
  2. 您提到您希望看到值,即使它们已过期。这与我所知道的大多数缓存实现中使用的到期抽象背道而驰。
  3. 在调用错误时返回先前缓存的值显然是特定于用例的。 Spring抽象只会将错误返回给用户。 CacheErrorHandler机制仅处理与缓存调用相关的异常。

总而言之,在我看来,您所要求的是非常特定于用例的,因此不是抽象将/不应该提供的。

© www.soinside.com 2019 - 2024. All rights reserved.