一、什么是 aop?
面向切面的编程:把问题一个分成不同的层面,解决问题时,动态的将需要的代码写入到指定的类的方法和指定的位置。
使用的场景:拦截器、(登录验证,验证码、事务管理的注解,日志文件,redis)
二、为什么要使用 aop ?
因为 aop 可以将一些共性的功能代码进行统一的管理,从而实现代码的解耦和复用
eg:Token的例子
三、如何使用 aop?
what?
1)判断 redis 里面有没有数据
2)congredis 里面提取数据插入到 ResultVO 里面
3)没有调用 controller 中service 方法正常结束流程。把返回值添加到 redis 里面
how?
1)先实现一个aop的功能。在调用controller之前去进行方法拦截。(@before,@around)
*跳过执行方法:before和around哪一个可以做到前面那一点
经测试:使用before的时候,会报ProceedingJoinPoint is only supported for around advice异常。所以我们只剩下唯一答案,就是使用around通知。
2) 与上述需求结合
逼逼叨终于开写了 创建 ExampleForAop
//定义的一个切面
@Aspect
public class ExampleForAop {
//定义一个切点作用于
//within 模糊的描述 excecutable()是确切的描述
//通配符.. 是省略包的其他方法和内容
//通配符* 是表示具体任何一个方法
@Pointcut("within(com.xlj.erp.controller.*)")
private void allmethods(){}
//进入方法以前
@Before(value = "execution(* com.xlj.erp.controller.AccountController.find(..))")
private void before(){
System.out.print("进入controller 可以做的事");
}
//完成以后
@AfterReturning(value = "execution(* com.xlj.erp.controller.AccountController.find(..))",returning = "returnVal")
private void after(Object returnVal){
System.out.print("返回值:"+returnVal);
}
//出现异常时
@AfterThrowing(value = "execution(* com.xlj.erp.controller.AccountController.find(..))")
private void throwErr(){
System.out.print("抛出异常的时候");
}
//通知
@Around(value = "execution(* com.xlj.erp.controller.AccountController.find(..))")
private Object around(ProceedingJoinPoint jionPoint) throws Throwable {
System.out.print("方法执行之前");
//方法的执行(这句话不走可以直接跳过方法体)
Object object=jionPoint.proceed();
System.out.print("方法执行之后");
return object;
}
}
二、进入主题用 aop 和 redis 配合使用制作一个 经办人下拉框的缓存 在创建一个 aop 测试类 ExampleForAop2
@Aspect
public class ExampleForAop2 {
@Autowired
private RedisTemplate redisTemplate;
//切点
@Pointcut("within(com.xlj.erp.controller..*)")
public void allMethod()
{}
//作用的方法上面
@Around(value = "execution(* com.xlj.erp.controller.InStoreRecordController.loadUserName())")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
//第一步判断 redis 里面是否有经办人的列表 如果有直接返回数据 不用运行 controller 的方法体
if (redisTemplate.hasKey("userList"))
{
//因为controller 的返回值是 returnVO 对象所以 new 一个 returnVO 的对象
ResultVO resultVO=new ResultVO();
//把 redis 经办人列表的数据从0位置到最后的位置全部放到 returnVO 的 list 属性里面
resultVO.setList(redisTemplate.opsForList().range("userList",0,redisTemplate.opsForList().size("userList")));
//输出
return resultVO;
}
//redis 里面没有经办人的列表
else
{
//执行 controller 的方法体
Object obj=joinPoint.proceed();
//方法的返回值可以就是 Obj 转化成 returnvo 类型
ResultVO resultVO=(ResultVO) obj;
//向redis 里面添加数据
redisTemplate.opsForList().leftPush("userList",resultVO.getList());
//输出
return obj;
}
//如果 redis 里面出现任何错误 只要执行原来的方法体即可
//redis 是为了优化数据库处理错误会干扰正常的主线出现问题执行原来的方法提就行不用处理报错
} catch (Exception e) {
Object obj=joinPoint.proceed();
return obj;
}
}
}