一、环绕通知
(1)环绕通知是所有通知类型中功能最为强大的,能够全面地控制连接点,甚至可以控制是否执行连接点;
(2)对于环绕通知来说,连接点的参数类型必须是 ProceedingJoinPoint。它是 JoinPoint 的子接口,允许控制何时执行,是否执行连接点;
(3)在环绕通知中需要明确调用 ProceedingJoinPoint 的 proceed() 方法来执行被代理的方法。如果忘记这样做就会导致通知被执行了,但目标方法没有被执行;
(4)注意:环绕通知的方法需要返回目标方法执行之后的结果,即调用 joinPoint.proceed() 的返回值,否则会出现空指针异常;
环绕通知:
/** * @Around:环绕:是Spring 中强大的通知,本质就是动态代理 * * try{ * //前置通知 * method.invoke(obj,args); * //返回通知 * }catch(e){ * //异常通知 * }finally{ * //后置通知 * } * * 四合一通知就是环绕通知 * 环绕通知中有一个参数:ProceedingJoinPoint pjp */ @Around("myPoint()") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { String methodName = pjp.getSignature().getName(); Object[] args = pjp.getArgs(); Object proceed = null; try { //@Before System.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】"); //就是利用反射调用目标方法即可,就是 method.invoke(obj, args) proceed = pjp.proceed(args); //@AfterReturning System.out.println("【环绕返回通知】---"+ methodName +"---【方法返回,返回值 "+ proceed +"】"); } catch (Exception e) { //@AfterThrowing System.out.println("【环绕异常通知】---"+ methodName +"---【方法出现异常】,异常信息:" + e); } finally { //@After System.out.println("【环绕后置通知】---"+ methodName +"---【方法结束】"); } //反射调用后的返回值也一定返回出去,不返回会空指针 return proceed; }
二、环绕通知顺序&抛出异常让其他通知感受到
当同时使用了环绕通知和普通通知,再来看一下执行顺序:
/* * 环绕通知:是优先于普通通知执行,执行顺序: * * 普通通知: * [普通前置] * 目标方法执行 * [普通后置] * [普通方法返回/方法异常] * * * 普通通知+环绕通知 * * 【普通前置】 * * { * try{ * 环绕前置 * 环绕执行目标方法:目标方法执行 * 环绕返回 * }catch(){ * 环绕异常 * }finally * 环绕后置 * } * } * 【普通后置】 * 【普通方法返回/方法异常】 * * * * 新的顺序: * 环绕前置 --- 普通前置 --- 目标方法执行 --- 环绕返回/异常 --- 环绕后置 --- 普通返回/异常 --- 普通后置 * * * 注意:环绕通知的异常一定要抛出去 * */ @Around("myPoint()") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { String methodName = pjp.getSignature().getName(); Object[] args = pjp.getArgs(); Object proceed = null; try { //@Before System.out.println("【环绕前置通知】---"+ methodName +"---【方法开始】"); //就是利用反射调用目标方法即可,就是 method.invoke(obj, args) proceed = pjp.proceed(args); //@AfterReturning System.out.println("【环绕返回通知】---"+ methodName +"---【方法返回,返回值 "+ proceed +"】"); } catch (Exception e) { //@AfterThrowing System.out.println("【环绕异常通知】---"+ methodName +"---【方法出现异常】,异常信息:" + e); //为了让外界能知道这个异常,这个异常一定要抛出去 throw new RuntimeException(e); } finally { //@After System.out.println("【环绕后置通知】---"+ methodName +"---【方法结束】"); } //反射调用后的返回值也一定返回出去,不返回会空指针 return proceed; }
执行顺序:
注意:环绕通知里面的异常一定要抛出去。