做一个合格的程序猿之浅析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看看吧~

时间: 2024-10-21 01:51:25

做一个合格的程序猿之浅析Spring AOP源码(十五) 分析JdkDynamicAopProxy的invoke方法的相关文章

做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析

其实上一篇文章价值很小,也有重复造轮子的嫌疑,网上AOP的实例很多,不胜枚举,其实我要说的并不是这个,我想要说的就是上一节中spring的配置文件: 我们这边并没有用到我们上几节分析的哪几个AOP的主要实现类:ProxyFactoryBean.java , ProxyFactory.java ,AspectJProxyFactory.java ,在我们这个配置文件中,根本没有显示的去配置这些类,那么spring到底是怎么做到的呢? 大家可以这么想,spring到底是怎么去杀害目标对象的呢?真正的

做一个懒COCOS2D-X程序猿(一)停止手打所有cpp文件到android.mk

前言:"懒"在这里当然不是贬义词,而是追求高效,拒绝重复劳动的代名词!做一个懒COCOS2D-X程序猿的系列文章将教会大家在工作中如何偷懒,文章篇幅大多较短,有的甚至只是几行代码,争取把懒发挥到极致! 一.懒人说书 Android.mk中LOCAL_SRC_FILES需要罗列出所有参与编译的文件,这样在.cpp文件少的时候还可以一个一个添加,当有几百个文件的时候会十分的痛苦! 我们下看看TestCpp工程中的Android.mk文件: 这只是节选的一部分,大概只有50个左右吧,除数量多

做一个“有资格”程序猿

其实这篇文章是很早就想写一,一直忙到没时间,今天终于是空的,继本职业工作方案谈猿我个人的一些想法: 要想做一个我觉得是"亲密格"程序猿.该要做到下面几点: 代码规范,凝视清楚 要做一个好的程序猿,代码的质量是最重要的,代码是项目过程中最为重要的资源.有非常多程序猿认为写凝视太麻烦,还会花太多时间,尤其是非常多规模比較小的公司,更不会注重这一点,可是往往到了项目后期.乃至项目由他人接手后,维护的成本会变得非常高,代码阅读困难,凝视不具体甚至没有.维护人员须要靠自己去推測某个方法的具体功能

如何做一个合格的程序员

不知不觉做软件已经做了十年,有成功的喜悦,也有失败的痛苦,但总不敢称自己是高手,因为和我心目中真正的高手们比起来,还差的太远.世界上并没有成为高手的捷径,但一些基本原则是可以遵循的. 1. 扎实的基础.数据结构.离散数学.编译原理,这些是所有计算机科学的基础,如果不掌握他们,很难写出高水平的程序.据我的观察,学计算机专业的人比学其他专业的人更能写出高质量的软件.程序人人都会写,但当你发现写到一定程度很难再提高的时候,就应该想想是不是要回过头来学学这些最基本的理论.不要一开始就去学OOP,即使你再

做一个“懒惰”的程序猿

懒惰,算是本人的一大缺点,可是我发现,事物的两面性在懒惰上得到充分体现.懒惰,并不是一无是处. 比方,编写脚本. 本人编写脚本的原因有两个:一是省事,不用每次敲那么多东西.二是本人健忘,无法记得冗长的命令. 就拿IPC的代码来讲, IPC代码根文件夹中,有N多build-XXX.而每个build-XXX文件夹下的内容,则全然相似,都有一个set.sh. 这就是编译用的脚本. 随便拿出一个来,其内容大致例如以下: cmake .. -DCROSS_COMPILE=arm-hisiv100nptl-

做一个“合格”的程序员

其实这篇文章很早就想写了,一直忙的没有时间,今天总算得空,下面就针对程序员这个职业来说一说我个人的一些想法: 要想做一个在我认为是"合格"的程序员,那么应该要做到以下几点: 代码规范,注释清楚 要做一个好的程序员,代码的质量是最重要的,代码是项目过程中最为重要的资源,有很多程序员觉得写注释太麻烦,还会花太多时间,尤其是很多规模比较小的公司,更不会注重这一点,但是往往到了项目后期,乃至项目由他人接手后,维护的成本会变得非常高,代码阅读困难,注释不详细甚至没有,维护人员需要靠自己去猜测某个

做一个好的程序猿

我算是靠坑蒙拐骗进了程序员的门,然后一路狂奔.26 岁之前几乎没有任何写代码的经验,研究生毕业却意外选择了一家不可能提供培训的初创公司,在每日担忧公司倒闭.害怕被炒鱿鱼以及同事冷落白眼的三重压力下逆流而上,一年半后离职,已是拥有 500 万用户产品的后台主程.从前我对计算机技术心怀畏惧,认定技术高人一定有佛光笼罩,昼夜不息运键如飞日吐代码上万行.现在也算见过一些世面了,回首那段忐忑不安宛如初夜的过程,我却不发觉有任何的励志意味,而是视为一种理所当然.理想的程序员,和理想的建筑师.理想的财务师.理

做一个优雅的程序猿

一.一室不扫何以扫天下 1.  "5整洁":衣着整洁.床铺整洁.卧室整洁.办公桌(室)整洁.PC文件目录整洁有序: 2.   "每日洗漱",早晚刷牙,每天洗澡:内衣袜子每天更换,当天清洗: 3.   "出门前检查":衣着得体.发型整齐.随身物品干净整齐和有序: 二.言必行,行必果 1. 当日事,当日毕: 2. 学会日程管理,在规定的时间内完成事情: 3. 及时记录.总结.反馈 三.翩翩少年 1. 不妄言,言谈有条有理: 声音洪亮.吐字清晰: 2.

如何做一个合格的策划

今天以我自己的角度来谈一谈“如何做一个合格的策划”,一个合格的游戏策划,必须先具备以下几个基本条件:1. 对游戏炽烈的爱.2. 责任心.3. 活跃的大脑.4. 强大学习能力.5. 强大的领悟能力.6. 良好的工作习惯 一. 对游戏炽烈的爱 为什么把“对游戏炽烈的爱”列为第一条? 如果没有爱,那就没有激情!有激情才可以激发一个人的生命潜力,有激情才可以支持这个人在未来事业上走的更久,走的更远. 游戏研发是一个枯燥的过程,整天面对的是纷繁的系统设计.数值计算.玩家心理等.作为游戏策划需要时刻保持高昂