aop执行的分析

aop 执行的过程分析

aop使用的时候需要定义一个切入点, 然后围绕切入定编写5种通知的类型
@Before , @Around , @After, @AfterReturning, @AfterThrowing

那么这5中通知是如何运行的呢 ?  测试一把
/** 作用在方法上面 */
@Target(ElementType.METHOD)
/** 保留到运行时 */
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeCounter {

}

/**
 * 如果没有异常: around -->before -->切入点的target方法 -->after-->afterReturning
 * 如果有异常:   around -->before -->切入点的target方法 -->after-->afterThrowing  (around joinPoint.proceed() 后面的代码不执行了)
 *
 */

@Component
@Aspect
public class TimerCounterAspect {

    private static final Logger logger = LoggerFactory.getLogger(TimerCounterAspect.class);

    ThreadLocal<Map<ClassLoader, Long>> timeLocal = new ThreadLocal<>();

    //扫描包 com.example.mq.controller下的所有的类  && 有@TimeCounter注解的方法
    @Pointcut(value = "execution(* com.example.mq.controller.*.*(..)) && @annotation(com.example.mq.config.TimeCounter)")
    public void targetMethodCutPoint() {
    }

    @Before(value = "targetMethodCutPoint()")
    public void before(JoinPoint point) {
        logger.info("enter aop before method...");

    }


    @After(value = "targetMethodCutPoint()")
    public void after(JoinPoint point) {
        logger.info("enter aop after method...");
    }

    @Around(value = "targetMethodCutPoint()")
    public Object around(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        logger.info("开始执行{}方法的around", method.getName());
        try {
            Long startTime = System.currentTimeMillis();

            Object result = joinPoint.proceed();

            Long endTime = System.currentTimeMillis();

            logger.info("execute around {} spend {} ms", method.getName(), (endTime - startTime));

            logger.info("execute method :{} the final result is :{}", method.getName(), result == null ? null : result.toString());
            return result;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    @AfterReturning(value = "targetMethodCutPoint()")
    public void afterReturning(JoinPoint joinPoint){
        logger.info("after returning");
    }
    @AfterThrowing(value = "targetMethodCutPoint()")
    public void afterThrowing(JoinPoint joinPoint){
        logger.info("after throwing");
    }
}

@RestController
public class Test {

    @TimeCounter
    @RequestMapping("/test")
    public String test() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int a =1, b=0,c=a/b;
        return "ok";
    }
}

int a =1, b=0,c=a/b;

2019-04-30 15:34:13.682  INFO 9176 --- [nio-8080-exec-6] c.example.mq.config.TimerCounterAspect   : 开始执行test方法的around
2019-04-30 15:34:13.683  INFO 9176 --- [nio-8080-exec-6] c.example.mq.config.TimerCounterAspect   : enter aop before method...
java.lang.ArithmeticException: / by zeroa.lang.Thread.run(Thread.java:748)
2019-04-30 15:34:15.702  INFO 9176 --- [nio-8080-exec-6] c.example.mq.config.TimerCounterAspect   : enter aop after method...
2019-04-30 15:34:15.703  INFO 9176 --- [nio-8080-exec-6] c.example.mq.config.TimerCounterAspect   : after returning


//int a =1, b=0,c=a/b;

2019-04-30 15:35:24.103  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : 开始执行test方法的around
2019-04-30 15:35:24.103  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : enter aop before method...
2019-04-30 15:35:26.108  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : execute around test spend 2005 ms
2019-04-30 15:35:26.109  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : execute method :test the final result is :ok
2019-04-30 15:35:26.110  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : enter aop after method...
2019-04-30 15:35:26.110  INFO 3872 --- [nio-8080-exec-1] c.example.mq.config.TimerCounterAspect   : after returning

结论

如果没有异常: around -->before -->切入点的target方法 -->after-->afterReturning
如果有异常:   around -->before -->切入点的target方法 -->after-->afterThrowing  
(around joinPoint.proceed() 后面的代码不执行了)