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() 后面的代码不执行了)