做一个合格的程序猿之浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法
Posted BazingaLyncc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做一个合格的程序猿之浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法相关的知识,希望对你有一定的参考价值。
上一节我们已经分析了Proxyfactorybean如何去生成一个目标对象的代理的,这一节我们将浅析一下基于JDK动态代理的核心回调方法invoke的源代码:
首先先打开JdkDynamicAopProxy.java 如下
JdkDynamicAopProxy.java文件是实现了AopProxy和InvocationHandler这2个接口的
先讲AopProxy这个接口,如图所示,AopProxy接口就定义了2个方法
我们再看这个接口的继承关系
好了,作为原生的基于JDK的动态代理的JdkDynamicAopProxy已经很完美的返回了目标对象的代理,详细请看上一节内容
http://blog.csdn.net/linuu/article/details/50972036
再分析InvocationHandler这个接口,这个接口核心的方法就是invoke方法
invoke这个方法首先先定义了一些变量,暂时不看
上图中的红色框中有三个if:
第一个if是判断如果被代理的目标对象要执行的方法是equal则执行JdkDynamicAopProxy(即代理对象的equal)方法,然后就返回了,也就说spring不对equal方法进行AOP拦截
第二个if是判断如果被代理的目标对象要执行的方法是hashcode则执行JdkDynamicAopProxy(即代理对象的hashcode)方法,随即也返回,同理,spring也不对hashcode进行AOP拦截
第三个if是判断如果被代理的对象本身就是实现了Advised接口,也不做处理,直接执行,(spring的意思是不是我不做切面的切面呢?)
接着看下一个核心方法
看官方的英文注释,就知道目前要做的就是获取一下这个方法所有的拦截器,形成拦截链返回,进入getInterceptorsAndDynamicInterceptionAdvice这个方法
479和480两行是从缓存中寻找该方法的拦截链是否已经获取过(可能被代理对象的某个方法被调用过多次,调用第一次就会获取一次,后面多次调用时,则需从缓存中直接获取,无需多次获取,这样就会提高性能),如果已经获取过,直接返回
好了,我们这边肯定是第一次调用,接着看getInterceptorsAndDynamicInterceptionAdvice这个方法
上图中①部分先定义了一个拦截链的List大小最大为我们传入advisor的个数,然后查看我们传入的advisor是否也是IntroductionAdvisor这个接口的子类,IntroductionAdvisor这个接口我们没有分析过,这应该是基于类的拦截器,不能拦截类中的具体方法,没有PointcutAdvisor灵活,我们这边了解一下就可以了
然后程序要做的事就是循环每个我们传入的advisor,然后强转成pointAdvisor,②中最核心的就是当前拦截是否匹配当前要执行代理的方法(其实也就是判断当前的advisor的切点是否就是这样方法),我们上节讲过我们闯入的pointCut是一个“万能”的pointCut:
我们再看matches这个方法
这就是这个万能的pointcut能切类的任何方法的原因了(其实这边就是一个拦截器的过滤,应该我们在生产环境中,我们一般会用正则表达来定义切点(expression),因为并不是每个方法都需要切,会影响性能,所以②中matches这个方法很重要)
如果匹配了,则把其放入方法一上来就定义的interceptorList中
我们回到JdkDynamicAopProxy的invoke方法中,接着看
此时我们的拦截链当然不是空的,直接分析else,invocation就是invoke方法中第一行就定义的MethodInvocation,这里的invocation其实就是把所有的参数准备好:
参数整理就是把我们之前的代理,目标对象,拦截的method的名称,拦截方法的参数和拦截器链全部整合到了ReflectiveMethodInvocation这个类中
各位看官想一下,ReflectiveMethodInvocation这个类有了这么多的参数,就可以干自己想干的任何是,首先它可以直接执行目标对象的那个方法(有目标类的class,名称,参数)就可以执行了(怎么执行?别闹,名称写的很清楚了,Reflect!!!!),并且有了拦截器链,只要知道拦截器的类型是前置,后置,环绕的类型,就可以吧拦截器也给执行了,所以所有的东西一切都准备就绪了~
最后我们看看执行的过程吧 proceed()方法
好了,我们来看看spring如何执行的,首先线看拦截器链,默认从-1个执行(get(-1)?错了,下文先++this.currentInterceptorIndex,这样就从第0个开始执行拦截器
spring判断我们的切面是否是需要动态匹配切点,我们这边就是很普通的万能切点,所以不需要,不管是什么样的切点,最后都执行了invoke方法,且将自己传入(ReflectiveMethodInvocation)
因为我们实现的是MethodBeforeAdviceInterceptor
这边就是执行我们在MethodInvokeCountAdvice,和MethodLoggerAdvice实现的before方法this.currentInterceptorIndex
然后再递归调用,与上次不一样的是this.currentInterceptorIndex这个+1了,所以会执行下一个拦截器,到了最后一个会走:
最后执行切入点,也就是我们目标对象的方法
到此为止关于proxyFactoryBean基本就讲结束了,还是希望自己debug看看吧~
以上是关于做一个合格的程序猿之浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法的主要内容,如果未能解决你的问题,请参考以下文章