大体来说,操作缓存有两种方式。
一种是在需要操作缓存的方法内调用相应的缓存工具类的操作方法进行操作,如一个查询用户列表的方法中,查询出来一个用户列表,要将这个列表放入缓存,则调用缓存的set方法。
**这是一种弱智的,侮辱人的方法!!! **
另一种是通过AOP的方式进行操作,这里面大体又有两种,一种是通过规范方法名,即将需要操作缓存的方法统一加上一个前缀或者后缀。
这种方法也略显扯淡,因为bug写多了之后,会忘了命名这回事。
还有一种是通过自定义注解,操作缓存,即,在需要操作缓存的方法上加上一个自定义的注解。
如下:
1.自定义注解,其中,key决定执行何种缓存操作,value是嵌入缓存中key的特定字符,用于精准更新,expireTime是缓存失效时间。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Cacheable {
String key();
String value() default "";
int expireTime() default 3600;
}
2.AOP配置类
注意几点:
1.@Aspect,表示这是一个切面
2.@Component,需要注入到容器
3.@EnableAspectJAutoProxy,动态代理
4.@Pointcut,定义切点
5.@Around(“pointCut()”)定义咋切,此处是环绕切
如下:
@Aspect
@Component
@EnableAspectJAutoProxy
public class AOPConfig {
@Autowired
private RedisTemplate redisTemplate;
public static final String GET_CACHE_GET = "get";
public static final String GET_CACHE_query = "query";
public static final String GET_CACHE_select = "select";
public static final String GET_CACHE_list = "list";
public static final String SET_CACHE_ADD = "add";
public static final String SET_CACHE_INSERT = "insert";
public static final String SET_CACHE_SAVE = "save";
public static final String SET_CACHE_BATCH_INSERT = "batchInsert";
public static final String SET_CACHE_BATCH_UPDATE = "batchUpdate";
public static final String SET_CACHE_UPDATE = "update";
public static final String SET_CACHE_DELETE = "delete";
/**
* 获取缓存验证
*/
private static final Pattern GET_CACHE_PATTERN = Pattern.compile("^((get)|(query)|(select)|(list)).*$");
/**
* 更新缓存验证
*/
private static final Pattern SET_CACHE_PATTERN = Pattern.compile("^((add)|(insert)|(save)|(batchInsert)|(batchUpdate)|(update)|(delete)).*$");
@Pointcut("@annotation(acw.com.sys.annotation.Cacheable)")
public void pointCut(){
}
@Around("pointCut()")
public Object doCache(ProceedingJoinPoint point)throws Throwable{
Object result = null;
Object [] args = point.getArgs();
String arg = "";
if (args != null && args.length>0){
//获取目标方法第一个参数值
arg = String.valueOf(args[0]);
}
//获取目标方法所在类
String className = point.getTarget().toString().split("@")[0];
//获取目标方法名
String methodName = point.getSignature().getName();
//获取目标注解
Cacheable cacheable
= ((MethodSignature)point.getSignature()).getMethod().getAnnotation(Cacheable.class);
String redisKey = className + "." +cacheable.value()+ methodName +":" + arg;
//查询
if(GET_CACHE_PATTERN.matcher(cacheable.key()).matches()){
result = redisTemplate.opsForValue().get(redisKey);
if (result != null){//缓存有值
return result;
}
result = point.proceed();
if (result == null){
result = "不存在该数据";
}
//数据库查询的数据放入缓存
redisTemplate.opsForValue().set(redisKey,result,cacheable.expireTime(), TimeUnit.SECONDS);
}else if (SET_CACHE_PATTERN.matcher(cacheable.key()).matches()){//更新
result = point.proceed();//先更新,再删缓存
Set<String> keys = redisTemplate.keys(className+ "." +cacheable.value()+"*");
redisTemplate.delete(keys);
}
return result;
}
使用时:
如下:
@Cacheable(key = AOPConfig.GET_CACHE_GET,value = "permission")
@GetMapping(value = "/getPermissionTree")
@ResponseBody
@ApiOperation(value = "获取权限树形", notes="从ERP为用户设置权限时")
@ApiParam(value = "角色ID" ,name="roleId")
public Result<Map<String,Object>> getPermissionTree(Long roleId){
Result<Map<String,Object>> result = new Result<>();
Map<String,Object> map = RoleService.getSysPermissionTree(roleId);
result.setData(map);
result.setMessage("操作成功");
result.setFlag(true);
return result;
}
@Cacheable(key = AOPConfig.SET_CACHE_SAVE,value = "permission")
@PostMapping(value = "/saveSysRolePermissionRelation")
@ResponseBody
@ApiOperation(value = "构建角色权限关系", notes="从ERP为用户设置权限时")
@ApiImplicitParams({
@ApiImplicitParam(name = "roleId", value = "角色ID", required = true, dataType = "String"),
@ApiImplicitParam(name = "permissions", value = "权限ID集合,permissionId,ajax传参时设置traditional:true", required = true, dataType = "String")
})
public Result saveSysRolePermissionRelation(@RequestBody Map<String,Object> map){
if (map == null || map.isEmpty()){
return null;
}
try {
PermissionService.saveSysRolePermissionRelation(map);
flag = true;
message = "操作成功";
}catch (Exception e){
e.printStackTrace();
message = e.getMessage();
flag = false;
}
return Result.init(flag,message,null);
}
上述示例中,第一个方法中@Cacheable(key = AOPConfig.GET_CACHE_GET,value = "permission")
表示对缓存进行插入操作,其key格式为className + "." +cacheable.value()+ methodName +":" + arg;
即,类名+“.”注解中的value+方法名+该方法第一个参数的值。如此可保证缓存精准。
第二个方法中@Cacheable(key = AOPConfig.SET_CACHE_SAVE,value = "permission")
表示对缓存进行更新操作,其实所谓的更新也就是删除缓存,根据className+ "." +cacheable.value()+"*"
删除,即该类下所有的该value的缓存都删除,大体上可以实现精准操作。
以上可以看出,使用自定义注解时,其value的值需要按需求精准设置,以此保证缓存操作的精准。
本项目使用的redis,工具类就不放了,满大街都是。