在使用springboot开发项目的时候,我们经常会用到缓存,一般就是通过注解@Cacheable来进行缓存设置。
我们代码是写了@Cacheable,我们以为能生效,但有时候因为一些原因,导致缓存不生效,程序也能正常运行,而我们却蒙在鼓里。如果是redis,虽然可以通过客户端去登录服务器查看有没有缓存,但也十分麻烦。
为了省点事,所以想到使用AOP来自动进行缓存检查,如果没有生效,就打印一些信息提示我们。
实现步骤很简单,只需要在springboot工程中添加上一个AOP类即可,并在配置文件中添加cacheable.check.switch=1
/**
* 不要设置order,否则该AOP将会在@Cacheable之前执行,就无法检测缓存是否起作用了
* 仅支持对方法级的@Cacheable进行检测,默认是以方法的所有参数作为key
* 不支持缓存缓存更新,重新缓存的情况(会判断为缓存失效,可以自己完善实现处理@CacheEvict)
*/
@Aspect
@Component
@ConditionalOnProperty(name = "cacheable.check.switch",havingValue = "1")
public class CacheableCheckAop {
//针对每个缓存,都有自己的一个set
private Map<String, Set<String>> cache = new ConcurrentHashMap<>();
//存放失效缓存的集合
private Set<String> unValidCache = new HashSet<>();
@Around("@annotation(cacheable)")
public Object before(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable{
Object[] args = joinPoint.getArgs();
String value = String.join("_", cacheable.value());
if(!unValidCache.contains(value)) {
if (!cache.containsKey(value)) {
synchronized (cache) {
if (!cache.containsKey(value)) {
cache.put(value, new HashSet<>());
}
}
}
String key = Arrays.stream(args).map(String::valueOf).collect(Collectors.joining("_"));
Set<String> set = cache.get(value); //同一个缓存同一个key,如果多次调用了,说明缓存失效
if (set.contains(key)) {
System.err.println(value + "缓存无效,key:" + key);
unValidCache.add(value);
} else {
set.add(key);
}
}
try {
return joinPoint.proceed();
}finally {
}
}
}
缓存失效的情况:
1.工程中忘记打开@EnableCaching
2.方法调用同一个类的另一个注解了@Cacheable方法
例如上面的这些,该AOP都可以提示缓存失效,不用我们再人为去检查了。
总结:
通过AOP,在原有缓存基础上,再实现我们的简单缓存,如果相同的key,调用了两次,就判断为缓存没有起作用