若不想看演示,请直接撸到最后(锚点怎么设)
各种通知
- 前置通知(Before):在目标方法执行之前执行
- 异常通知(AfterThrowing):当目标方法执行过程中出现异常时执行
- 后置通知(AfterReturning):当目标方法能正常结束后执行
- 最终通知(After):无论目标方法能否正常结束都会执行
- 环绕通知(Around):伴随目标方法各个时期(前面四种通知的综合)
执行顺序
一. 目标方法无异常时
1. 整一个目标方法(切面)就以某Controller方法为例吧
@RestController
public class TestAdvice {
@RequestMapping("/test/advice")
public String test(){
System.out.println("Controller.test()正在干活...");
return "yes";
}
}
2. 写一个aop类,造一堆通知
@Component
@Aspect
public class MyAdvice {
private final
String execution = "execution(public String controller.TestAdvice.test())";
@Before(execution)
public void before(){
System.out.println("Before通知执行了");
}
@AfterReturning(value = execution, returning = "value")
public String afterReturning(String value){
System.out.println("AfterReturning通知执行了");
//原封不动的返回出去
return value;
}
@AfterThrowing(value = execution, throwing = "th")
public void afterThrowing(Throwable th){
System.out.println("AfterThrowing通知执行了," + th.getMessage());
//当目标方法出现未捕获的异常时,不知道先触发本方法,还是先触发Around里的catch块
//所以再抛一个异常,如果先触发本方法,那Around的catch块里应该打印下面这句话
throw new RuntimeException("来自AfterThrowing的异常");
}
@After(execution)
public void after(){
System.out.println("After通知执行了");
}
@Around(execution)
public String around(ProceedingJoinPoint pjp){
try{
System.out.println("Around.before执行了");
pjp.proceed();
System.out.println("目标方法已执行完毕");
return "yes";
}catch (Throwable throwable) {
System.out.println("Around.afterThrowing执行了, " + throwable.getMessage());
} finally {
System.out.println("Around.after执行了");
}
return "no";
}
}
3.完活,浏览器访问
4.看控制台
5.结论
Around.before > Before > Around.after > After > AfterReturning
再废两句话
二. 目标方法有异常时
在上面的 Controller.test()
添加一条测试异常全国通用语句
@RestController
public class TestAdvice {
@RequestMapping("/test/advice")
public String test(){
System.out.println("Controller.test()正在干活...");
int i = 1 / 0; //往这看
return "yes";
}
}
浏览器访问
看控制台
结论
Around.afterThrowing > AfterThrowing
Around通知就是这么横!它抢先AfterThrowing一步,直接把异常处理了,然后就没AfterThrowing啥事儿了。顺理成章的,当异常被消灭后,AfterReturning也蹦了出来
如果上面的结论是对的,那把Around里的catch注释掉,结果应该是AfterThrowing会执行
@Around(execution)
public String around(ProceedingJoinPoint pjp) throws Throwable {
try{
System.out.println("Around.before执行了");
pjp.proceed();
System.out.println("目标方法已执行完毕");
return "yes";
}
/*catch (Throwable throwable) {
System.out.println("Around.afterThrowing执行了, " + throwable.getMessage());
} */
finally {
System.out.println("Around.after执行了");
}
}
可以看到,AfterThrowing确实冒出来了,证明上面的结论是对的
而且这次AfterReturning并没有出现。
注意:AfterThrowing方法只是当目标方法存在未捕获的异常时被动执行,人家压根就不负责catch;而浏览器显示的异常是被AfterThrowing方法内我们手动抛出的异常覆盖了
三. 总结
- Around是老大,优先级最高
Around.before 先于 Before
Around.after 先于 After
Around.afterThrowing 先于 AfterThrowing - Before > After > AfterThrowing