如何暂时禁用 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()
);
}
我有一个 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()
);
}