Springboot内置了缓存,spring-cache
首先添加对应的依赖
<!--添加springboot缓存的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
启动类上添加@EnableCaching,用于开启缓存
在需要缓存的方法上,添加@Cacheable,当方法查询的内容存在于缓存中,则直接从缓存中获取值,否则再去按照方法中的实现去数据库查询并添加到缓存中
//key:缓存的键,使用"#方法形参名称"绑定缓存的键,如果不写,默认绑定方法上所有的形参
@Cacheable(value = "具体的缓存名称,自己命名",key = "#xxx")
public Student getStudent(String id){
Student student= StudentMapper.selectOne(new QueryWrapper<Student >()
.eq("id", id));
return student;
}
在修改、删除方法上添加@CacheEvict用于删除缓存
@CacheEvict(value = "user", key = "'A'") //删除user模块下名称为A的key也就是user::a
@CacheEvict(value = "user", allEntries = true) //删除user模块下所有key;
但是,@CacheEvict不支持多选删除,即无法用于批量删除等操作,因此,需要引入自定义注解来实现!!!
添加一个注解类
/**
* 由于SpringCache自带的@CacheEvict不支持批量删除,自定义注解实现
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheBatchEvict {
/**
* 指定缓存组件
*/
String[] cacheNames() default {};
/**
* key需要指定一个spEL表达式,通过spEL表达式获取方法参数
*/
String key() default "";
/**
* 是否清除所有
*/
boolean isClearAll() default false;
}
添加一个切面类
@Aspect
@Component
public class CacheBatchEvictAspect {
@Autowired
private CacheManager cacheManager;
/**
* 定义切入点
*/
@Pointcut("@annotation(cn.com.dhcc.datafilling.aspect.annotation.CacheBatchEvict)")
public void pointcut() {
}
@Around("pointcut()")
public Object proceed(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 1.获取注解参数值 SpEL表达式
CacheBatchEvict cacheBatchEvict = methodSignature.getMethod().getAnnotation(CacheBatchEvict.class);
String[] cacheNames = cacheBatchEvict.cacheNames();
// 清空所有缓存
if (cacheBatchEvict.isClearAll()) {
for (String cacheName : cacheNames) {
Cache cache = Objects.requireNonNull(cacheManager.getCache(cacheName));
cache.clear();
}
}
String spEL = cacheBatchEvict.key();
if (!StringUtils.hasText(spEL)) {
return null;
}
// 2.获取目标方法参数
List<Object> keyList = generateKeyListBySpEL(spEL, joinPoint);
if (keyList == null) {
return null;
}
// 3.清除缓存
for (String cacheName : cacheNames) {
Cache cache = Objects.requireNonNull(cacheManager.getCache(cacheName));
for (Object key : keyList) {
if(cache.evictIfPresent(key)){
cache.evict(key);
}
}
}
// 4.执行目标方法
return joinPoint.proceed();
}
public List<Object> generateKeyListBySpEL(String spEL, ProceedingJoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 创建解析器
SpelExpressionParser parser = new SpelExpressionParser();
// 获取表达式
Expression expression = parser.parseExpression(spEL);
// 设置解析上下文
EvaluationContext context = new StandardEvaluationContext();
Object[] args = joinPoint.getArgs();
// 获取运行时参数名称
DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
String[] parameterNames = discover.getParameterNames(method);
assert parameterNames != null;
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i]);
}
// 解析
List<Object> valueList = (List<Object>) expression.getValue(context);
if (CollectionUtils.isEmpty(valueList)) {
return null;
}
return valueList;
}
}
使用时
@CacheBatchEvict(cacheNames = {"自定义的缓存名称"},key = "#形参名称")