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







注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com