如何暂时禁用 Spring 缓存的缓存

How to temporarily disable caching for Spring cache

我有一个 spring bean 用 @Cacheable 定义的注释注释

@Service
public class MyCacheableBeanImpl implements MyCacheableBean {
    @Override
    @Cacheable(value = "cachedData")
    public List<Data> getData() { ... }
}

我需要此 class 能够禁用缓存并仅处理来自原始来源的数据。这应该基于来自外部的某些事件而发生。这是我的方法:

@Service
public class MyCacheableBeanImpl implements MyCacheableBean, ApplicationListener<CacheSwitchEvent> {
    //Field with public getter to use it in Cacheable condition expression
    private boolean cacheEnabled = true;

    @Override
    @Cacheable(value = "cachedData", condition = "#root.target.cacheEnabled") //exression to check whether we want to use cache or not
    public List<Data> getData() { ... }

    @Override
    public void onApplicationEvent(CacheSwitchEvent event) {
        // Updating field from application event. Very schematically just to give you the idea
        this.cacheEnabled = event.isCacheEnabled();
    }

    public boolean isCacheEnabled() {
        return cacheEnabled;
    }

}

我担心的是这种方法中 "magic" 的级别非常高。我什至不确定如何测试它是否可行(基于 spring 文档,这应该可行,但如何确定)。我做对了吗?如果我错了,如何改正?

我要找的是 NoOpCacheManager:

为了让它工作,我从 xml bean 创建切换到工厂

我做了如下事情:

    @Bean
public CacheManager cacheManager() {
    final CacheManager cacheManager;        
    if (this.methodCacheManager != null) {
        final EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
        ehCacheCacheManager.setCacheManager(this.methodCacheManager);
        cacheManager = ehCacheCacheManager;
    } else {
        cacheManager = new NoOpCacheManager();
    }

    return cacheManager;
}

受 SimY4 上一条评论的启发,这里是我的工作解决方案重载 SimpleCacheManager 以提供运行时切换。 只需使用switchableSimpleCacheManager.setEnabeld(false/true)切换off/on.

package ch.hcuge.dpi.lab.cache;

import org.springframework.cache.Cache;
import org.springframework.cache.support.NoOpCache;
import org.springframework.cache.support.SimpleCacheManager;

/**
* Extends {@link SimpleCacheManager} to allow to disable caching at runtime
*/
public class SwitchableSimpleCacheManager extends SimpleCacheManager {

  private boolean enabled = true;

  public boolean isEnabled() {
      return enabled;
  }

/**
 * If the enabled value changes, all caches are cleared
 *
 * @param enabled true or false
 */
public void setEnabled(boolean enabled) {
    if (enabled != this.enabled) {
        clearCaches();
    }
    this.enabled = enabled;
}

@Override
public Cache getCache(String name) {
    if (enabled) {
        return super.getCache(name);
    } else {
        return new NoOpCache(name);
    }
}

protected void clearCaches() {
    this.loadCaches().forEach(cache -> cache.clear());
}

}

配置(使用咖啡因):

@Bean
public SwitchableSimpleCacheManager cacheManager() {
    SwitchableSimpleCacheManager cacheManager = new SwitchableSimpleCacheManager();
    cacheManager.setCaches(Arrays.asList(
            buildCache(RESULT_CACHE, 24, 5000)
    ));
    return cacheManager;
}

private CaffeineCache buildCache(String name, int hoursToExpire, long maxSize) {
    return new CaffeineCache(
            name,
            Caffeine.newBuilder()
                    .expireAfterWrite(hoursToExpire, TimeUnit.HOURS)
                    .maximumSize(maxSize)
                    .build()
    );
}