一:调用AOP 代理对象
本章结合源码讲解AOP的代理对象创建完成是如何调用的。
1,调用AOP代理类的方法
假设Calculate类是切点,里面有一个add方法。此时执行Calculate.add的方法的时候直接进入JdkDynamicAopProxy类中的invoke方法。
2,invoke方法
不用想在调用到这里的时候肯定是invoke的方法对增强器进行调用,那么看看它都做了什么事情。
1,判断equals、hashcode、.getDeclaringClass()、advised.opaque这些个东东都不进行代理调用。
2,oldProxy = AopContext.setCurrentProxy(proxy);
这句话的意识是说要不要暴露我的代理对象。举个例子:它就是处理@EnableAspectJAutoProxy(exposeProxy = true)。处理exposeProxy = true的。如果为true就进行暴露。3
3,this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
获取拦截器链,将获取到的方法的切面,转化为拦截器链。通过getInterceptorsAndDynamicInterceptionAdvice方法从缓存拿,拿不到通过该方法进行解析再放入缓存
4,chain.isEmpty()
判断是否为空如果为空直接进行反射调用,通过invokeJoinpointUsingReflection进行反射调用。
5,ReflectiveMethodInvocation
创建一个反射的方法调用,创建一个对象
6,invocation.proceed()最最最最重要的方法;AOP的核心思想就在这个方法里。
这里面有个小的算法this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1递归调用。currentInterceptorIndex初始值-1,我们知道走到这里的时候正常去掉我们的目标方法。但是调用目标方法不是随便调用的,而是有顺序的,在上面,将代理的切面转换成拦截器链的时候,进行了排序,下面看一张图,是增强器的执行流程。由图可知,前置方法最先执行,然后目标方法,然后后置方法,返回通知和异常通知只能执行一个。所以在这里面Spring用了一个非常巧妙的设计方式-------递归。
7,递归调用执行增强器如下图
如图可知,currentInterceptorIndex 初始值是1,this.interceptorsAndDynamicMethodMatchers.size() 这是增强器的总数。如果这个表达式成立的时候,才调用目标方法。当currentInterceptorIndex==-1的时候。不相等就往下走。走到((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)。这里是动态代理调用。this,代表当前类的引用。第一次进来的时候又执行了一次proceed方法。
8,(MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
当第二次调用回来的时候currentInterceptorIndex 变为0,执行下标为1的拦截器。调用了异常增强器。然后走到invoke方法进去看下,如第二个如所知,如果抛异常才调用invokeAdviceMethod方法。所以这里不进行拦截。接着往后看。
9,currentInterceptorIndex ==3的时候。直接进入invoke方法中,可以看到如下图的方法,如图可知before方法先执行了。然后又回到proceed方法。此时currentInterceptorIndex ==4.正好满足条件可以执行目标发放,此时打印目标方法信息。此时执行完以后。回退到之前未执行完的递归调用。以此类推。最后退出。此时,增强器调用完毕。
总结:总结一下AOP的增强器调用的核心思想。
1:在把增强器转化成拦截器链的时候,对切面进行了排序。根据执行的顺序可知,before方法,总是在目标方法前面的一个位置。但是调用的时候是最后调用的。但是,通过代码断点可知,最后执行的,最先被打印,以此类推,也就是说,最先执行的,确实最后被真正的调用。从前调用,从后执行。
2:使用了动态代理模式和责任链模式,通过责任链去递归调用动态代理的invoke方法,执行不同的切面,然后又都调用proceed方法进行递归
3:BeforeAdvice总是在目标方法执行之前调用。通过currentInterceptorIndex==his.interceptorsAndDynamicMethodMatchers.size() -1的算法。
4:最后附赠一张,增强器的调用流程图。