SpringAOP学习之5种通知

一、Spring的AOP分为以下5种类型通知

①前置通知(Before):在连接点执行前执行该通知

②正常返回通知(AfterReturning):在连接点正常执行完后执行该通知,若目标方法执行异常则不会执行该通知

③异常返回通知(AfterThrowing):在连接点执行抛出异常时执行该通知

④后置通知(after/finally):在连接点执行完成后(不管成功、失败、异常)都会执行该通知

⑤环绕通知(Around):围绕在连接点前后

二、执行顺序

1、正常执行

①环绕通知:@Around

②前置通知:@Before

③连接点方法执行

④环绕通知:@Around

⑤后置通知:@After

⑥正常返回通知:@AfterReturning

  其他结论说出来也没意思,还是自己通过简单demo测试一下就出来了

三、测试

1、自定义注解

2、切面

@Aspect
@Component
@Slf4j
public class LogAspect {
    //切点范围
    @Pointcut("@annotation(com.test.annotation.OperateLog)")
    public void operateMethod(){}
    //前置通知
    @Before("operateMethod()")
    public void before(){
        log.info("前置通知:Before");
    }
    //正常返回通知
    @AfterReturning("operateMethod()")
    public void afterReturning(){
        log.info("后置通知:AfterReturning");
    }
    //后置通知
    @After("operateMethod()")
    public void after(){
        log.info("后置通知:After");
    }
    //异常返回通知
    @AfterThrowing("operateMethod()")
    public void afterThrowing(){
        log.info("异常返回通知:AfterThrowing");
    }
    //环绕通知
    @Around("operateMethod()")
    public Object methodAround(ProceedingJoinPoint joinPoint) throws Throwable{
        log.info("环绕通知:around------前");
        Object result=null;
        OperateLog annotation = getAnnotation(joinPoint);
        try {
            result=joinPoint.proceed();
        } catch (Throwable throwable) {
            log.info("环绕通知:around------异常");
        }
        try {
            String system = annotation.system();
            int flag = annotation.flag();
            String operatorName = annotation.operatorName();
            log.info("切面校验信息,系统:【{}】,标识:【{}】,操作员名称:【{}】", system,flag,operatorName);
            //日志入库业务
        } catch (Exception e) {
            log.info("切面异常",e);
        }
        log.info("环绕通知:around------后");
        return result;
    }

    private OperateLog getAnnotation(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getAnnotation(OperateLog.class);
    }
}
切面代码

3、定义service接口并实现

service接口

 实现类

 4、测试controller

@RestController
@Slf4j
public class LogController {
    @Autowired
    private IHelloService helloService;

    @RequestMapping("/test")
    @OperateLog(system = "系统1",flag = 1,operatorName = "操作员1")
    public void test() throws Exception {
        OperateLog test = (OperateLog)AnnotationUtil.getAnnotation(LogController.class, OperateLog.class, "test", 1);
        log.info("更改前的注解属性:【{}】,【{}】,【{}】",test.flag(),test.operatorName(),test.system() );
        //更改注解OperateLog的system属性值为“系统2”
        AnnotationUtil.ModifyAnnotation(LogController.class, OperateLog.class, "test", "system", "系统2");
        //更改flag的属性值为2
        AnnotationUtil.ModifyAnnotation(LogController.class, OperateLog.class, "test", "flag", 2);
        //更改注解的operatorName属性值为:张三
        AnnotationUtil.ModifyAnnotation(LogController.class, OperateLog.class, "test", "operatorName", "张三");
        log.info("更改后的注解属性:【{}】,【{}】,【{}】",test.flag(),test.operatorName(),test.system() );
    }
    @RequestMapping("/test1")
    @OperateLog(system = "系统1",flag = 1,operatorName = "操作员1")
    public void test1() throws Exception {
        helloService.IsayHello();
    }
    @RequestMapping("/test2")
    @OperateLog(system = "系统1",flag = 1,operatorName = "操作员1")
    public void test2() throws Exception {
        helloService.say("我是controller");
    }
    @RequestMapping("/test3")
    @OperateLog(system = "系统1",flag = 1,operatorName = "操作员1")
    public void test3() throws Exception {
        helloService.error(true);
    }
    @RequestMapping("/test4")
    @OperateLog(system = "系统1",flag = 1,operatorName = "操作员1")
    public void test4() throws Exception {
        helloService.error(false);
    }
}
controller

 5、测试

 三、总结

1、Aop可以理解为一个同心圆,要执行的目标方法(底层还是jdk或cglib动态代理)为圆心,最外层的order最小,环绕、前置通知先执行,后置、正常返回通知后执行

2、多个aop执行的执行顺序可以使用@Order注解来实现

本项目地址https://github.com/Simple-Coder/aop-demo

posted @ 2019-11-11 20:48  coder、  阅读(794)  评论(0编辑  收藏  举报