通知

高级通知到低级通知

  1. @Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
    1. 通知代码从哪儿来
    2. 切点是什么(可能需要切点的方法参数信息)
    3. 通知对象如何创建, 本例共用同一个 Aspect 对象
  1. 类似的还有
    1. AspectJAroundAdvice (环绕通知)
    2. AspectJAfterReturningAdvice
    3. AspectJAfterThrowingAdvice (环绕通知)
    4. AspectJAfterAdvice (环绕通知)
 
public class A17_2 { static class Aspect { @Before("execution(* foo())") public void before1() { System.out.println("before1"); } @Before("execution(* foo())") public void before2() { System.out.println("before2"); } public void after() { System.out.println("after"); } public void afterReturning() { System.out.println("afterReturning"); } public void afterThrowing() { System.out.println("afterThrowing"); } public Object around(ProceedingJoinPoint pjp) throws Throwable { try { System.out.println("around...before"); return pjp.proceed(); } finally { System.out.println("around...after"); } } } static class Target { public void foo() { System.out.println("target foo"); } } @SuppressWarnings("all") public static void main(String[] args) throws Throwable { AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect()); // 高级切面转低级切面类 List<Advisor> list = new ArrayList<>(); for (Method method : Aspect.class.getDeclaredMethods()) { if (method.isAnnotationPresent(Before.class)) { // 解析切点 String expression = method.getAnnotation(Before.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } } for (Advisor advisor : list) { System.out.println(advisor); } } }

静态通知调用

通知统一转换为环绕通知 MethodInterceptor

其实无论 ProxyFactory 基于哪种方式创建代理, 最后干活(调用 advice)的是一个 MethodInvocation 对象
  1. 因为 advisor 有多个, 且一个套一个调用, 因此需要一个调用链对象, 即 MethodInvocation
  1. MethodInvocation 要知道 advice 有哪些, 还要知道目标, 调用次序如下
    1. 将 MethodInvocation 放入当前线程 |-> before1 ----------------------------------- 从当前线程获取 MethodInvocation | | | |-> before2 -------------------- | 从当前线程获取 MethodInvocation | | | | | | |-> target ------ 目标 advice2 advice1 | | | | | |-> after2 --------------------- | | | |-> after1 ------------------------------------
  1. 从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知
  1. 统一转换为环绕通知, 体现的是设计模式中的适配器模式
    1. 对外是为了方便使用要区分 before、afterReturning
    2. 对内统一都是环绕通知, 统一用 MethodInterceptor 表示
    3.  
public class A18 { static class Aspect { @Before("execution(* foo())") public void before1() { System.out.println("before1"); } @Before("execution(* foo())") public void before2() { System.out.println("before2"); } public void after() { System.out.println("after"); } @AfterReturning("execution(* foo())") public void afterReturning() { System.out.println("afterReturning"); } @AfterThrowing("execution(* foo())") public void afterThrowing(Exception e) { System.out.println("afterThrowing " + e.getMessage()); } @Around("execution(* foo())") public Object around(ProceedingJoinPoint pjp) throws Throwable { try { System.out.println("around...before"); return pjp.proceed(); } finally { System.out.println("around...after"); } } } static class Target { public void foo() { System.out.println("target foo"); } } @SuppressWarnings("all") public static void main(String[] args) throws Throwable { AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect()); // 1. 高级切面转低级切面类 List<Advisor> list = new ArrayList<>(); for (Method method : Aspect.class.getDeclaredMethods()) { if (method.isAnnotationPresent(Before.class)) { // 解析切点 String expression = method.getAnnotation(Before.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } else if (method.isAnnotationPresent(AfterReturning.class)) { // 解析切点 String expression = method.getAnnotation(AfterReturning.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } else if (method.isAnnotationPresent(Around.class)) { // 解析切点 String expression = method.getAnnotation(Around.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } } for (Advisor advisor : list) { System.out.println(advisor); } Target target = new Target(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(target); proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); // 准备把 MethodInvocation 放入当前线程 proxyFactory.addAdvisors(list); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); List<Object> methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class); for (Object o : methodInterceptorList) { System.out.println(o); } }
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before2()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before1()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.afterReturning()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name ''] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> org.springframework.aop.interceptor.ExposeInvocationInterceptor@7e07db1f org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@1189dd52 org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@36bc55de org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@564fabc8 org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name ''
 
 
代理方法执行时会做如下工作
  1. 通过 proxyFactory 的 getInterceptorsAndDynamicInterceptionAdvice() 将其他通知统一转换为 MethodInterceptor 环绕通知
      • MethodBeforeAdviceAdapter 将 @Before AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
      • AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
      • 这体现的是适配器设计模式
  1. 所谓静态通知,体现在上面方法的 Interceptors 部分,这些通知调用时无需再次检查切点,直接调用即可
  1. 结合目标与环绕通知链,创建 MethodInvocation 对象,通过它完成整个调用

适配器

MethodBeforeAdviceAdapter
/** * Adapter to enable {@link org.springframework.aop.MethodBeforeAdvice} * to be used in the Spring AOP framework. * * @author Rod Johnson * @author Juergen Hoeller */ @SuppressWarnings("serial") class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { @Override public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } @Override public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); } }
AfterReturningAdviceAdapter
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable { @Override public boolean supportsAdvice(Advice advice) { return (advice instanceof AfterReturningAdvice); } @Override public MethodInterceptor getInterceptor(Advisor advisor) { AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice(); return new AfterReturningAdviceInterceptor(advice); } }

Interceptor

MethodBeforeAdviceInterceptor
notion image

MethodIterceptor调用链

创建调用链对象,指定增强目标,方法,参数,需要执行的MethodIterceptor集合
MethodInvocation methodInvocation = new ReflectiveMethodInvocation( null, target, Target.class.getMethod("foo"), new Object[0], Target.class, methodInterceptorList ); methodInvocation.proceed();
 
把methodInvocation 对象放入对象线程,方便其他拦截器对象获取
proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); // 准备把 MethodInvocation 放入当前线程
 
public class A18 { static class Aspect { @Before("execution(* foo())") public void before1() { System.out.println("before1"); } @Before("execution(* foo())") public void before2() { System.out.println("before2"); } public void after() { System.out.println("after"); } @AfterReturning("execution(* foo())") public void afterReturning() { System.out.println("afterReturning"); } @AfterThrowing("execution(* foo())") public void afterThrowing(Exception e) { System.out.println("afterThrowing " + e.getMessage()); } @Around("execution(* foo())") public Object around(ProceedingJoinPoint pjp) throws Throwable { try { System.out.println("around...before"); return pjp.proceed(); } finally { System.out.println("around...after"); } } } static class Target { public void foo() { System.out.println("target foo"); } } @SuppressWarnings("all") public static void main(String[] args) throws Throwable { AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect()); // 1. 高级切面转低级切面类 List<Advisor> list = new ArrayList<>(); for (Method method : Aspect.class.getDeclaredMethods()) { if (method.isAnnotationPresent(Before.class)) { // 解析切点 String expression = method.getAnnotation(Before.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } else if (method.isAnnotationPresent(AfterReturning.class)) { // 解析切点 String expression = method.getAnnotation(AfterReturning.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } else if (method.isAnnotationPresent(Around.class)) { // 解析切点 String expression = method.getAnnotation(Around.class).value(); AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression); // 通知类 AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } } for (Advisor advisor : list) { System.out.println(advisor); } Target target = new Target(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(target); proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); // 准备把 MethodInvocation 放入当前线程 proxyFactory.addAdvisors(list); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); List<Object> methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class); for (Object o : methodInterceptorList) { System.out.println(o); } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); // 3. 创建并执行调用链 (环绕通知s + 目标) MethodInvocation methodInvocation = new ReflectiveMethodInvocation( null, target, Target.class.getMethod("foo"), new Object[0], Target.class, methodInterceptorList ); methodInvocation.proceed(); } }
methodInvocation.proceed(); 源码
notion image

MethodInvoation模拟实现

模拟调用链过程, 是一个简单的递归过程
  1. proceed() 方法调用链中下一个环绕通知
  1. 每个环绕通知内部继续调用 proceed()
  1. 调用到没有更多通知了, 就调用目标方法
public class A18_1 { static class Target { public void foo() { System.out.println("Target.foo()"); } } static class Advice1 implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Advice1.before()"); Object result = invocation.proceed();// 调用下一个通知或目标 System.out.println("Advice1.after()"); return result; } } static class Advice2 implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Advice2.before()"); Object result = invocation.proceed();// 调用下一个通知或目标 System.out.println("Advice2.after()"); return result; } } static class MyInvocation implements MethodInvocation { private Object target; // 1 private Method method; private Object[] args; List<MethodInterceptor> methodInterceptorList; // 2 private int count = 1; // 调用次数 public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) { this.target = target; this.method = method; this.args = args; this.methodInterceptorList = methodInterceptorList; } @Override public Method getMethod() { return method; } @Override public Object[] getArguments() { return args; } @Override public Object proceed() throws Throwable { // 调用每一个环绕通知, 调用目标 if (count > methodInterceptorList.size()) { // 调用目标, 返回并结束递归 return method.invoke(target, args); } // 逐一调用通知, count + 1 MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1); return methodInterceptor.invoke(this); } @Override public Object getThis() { return target; } @Override public AccessibleObject getStaticPart() { return method; } } public static void main(String[] args) throws Throwable { Target target = new Target(); List<MethodInterceptor> list = List.of( new Advice1(), new Advice2() ); MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], list); invocation.proceed(); } }

静态调用流程总结

代理对象调用流程如下(以 JDK 动态代理实现为例)
  • 从 ProxyFactory 获得 Target 和环绕通知链,根据他俩创建 MethodInvocation,简称 mi
  • 首次执行 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)
  • 进入环绕通知1,执行前增强,再次调用 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)
  • 进入环绕通知2,执行前增强,调用 mi.proceed() 发现没有环绕通知,调用 mi.invokeJoinPoint() 执行目标方法
  • 目标方法执行结束,将结果返回给环绕通知2,执行环绕通知2 的后增强
  • 环绕通知2继续将结果返回给环绕通知1,执行环绕通知1 的后增强
  • 环绕通知1返回最终的结果
图中不同颜色对应一次环绕通知或目标的调用起始至终结
notion image

动态通知调用

  1. 通过 proxyFactory 的 getInterceptorsAndDynamicInterceptionAdvice() 将其他通知统一转换为 MethodInterceptor 环绕通知
  1. 所谓动态通知,体现在上面方法的 DynamicInterceptionAdvice 部分,这些通知调用时因为要为通知方法绑定参数,还需再次利用切点表达式
  1. 动态通知调用复杂程度高,性能较低
public class A19 { @Aspect static class MyAspect { @Before("execution(* foo(..))") // 静态通知调用,不带参数绑定,执行时不需要切点 public void before1() { System.out.println("before1"); } @Before("execution(* foo(..)) && args(x)") // 动态通知调用,需要参数绑定,执行时还需要切点对象 public void before2(int x) { System.out.printf("before2(%d)%n", x); } } static class Target { public void foo(int x) { System.out.printf("target foo(%d)%n", x); } } @Configuration static class MyConfig { @Bean AnnotationAwareAspectJAutoProxyCreator proxyCreator() { return new AnnotationAwareAspectJAutoProxyCreator(); } @Bean public MyAspect myAspect() { return new MyAspect(); } } public static void main(String[] args) throws Throwable { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean(ConfigurationClassPostProcessor.class); context.registerBean(MyConfig.class); context.refresh(); AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class); List<Advisor> list = creator.findEligibleAdvisors(Target.class, "target"); Target target = new Target(); ProxyFactory factory = new ProxyFactory(); factory.setTarget(target); factory.addAdvisors(list); Object proxy = factory.getProxy(); // 获取代理 List<Object> interceptorList = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo", int.class), Target.class); for (Object o : interceptorList) { showDetail(o); } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>"); ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation( proxy, target, Target.class.getMethod("foo", int.class), new Object[]{100}, Target.class, interceptorList ) {}; invocation.proceed(); /* 学到了什么 a. 有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定 b. 复杂程度高, 性能比无参数绑定的通知调用低 */ } public static void showDetail(Object o) { try { Class<?> clazz = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher"); if (clazz.isInstance(o)) { Field methodMatcher = clazz.getDeclaredField("methodMatcher"); methodMatcher.setAccessible(true); Field methodInterceptor = clazz.getDeclaredField("interceptor"); methodInterceptor.setAccessible(true); System.out.println("环绕通知和切点:" + o); System.out.println("\t切点为:" + methodMatcher.get(o)); System.out.println("\t通知为:" + methodInterceptor.get(o)); } else { System.out.println("普通环绕通知:" + o); } } catch (Exception e) { e.printStackTrace(); } } }