官术网_书友最值得收藏!

3.6 Spring AOP的實(shí)現(xiàn)原理

Spring AOP的實(shí)現(xiàn)是通過創(chuàng)建目標(biāo)對象的代理類,并對目標(biāo)對象進(jìn)行攔截來實(shí)現(xiàn)的。分析Spring AOP的底層實(shí)現(xiàn),需要重點(diǎn)分析幾個(gè)常用類,相關(guān)類圖如3-15所示。

ProxyConfig類是一個(gè)基類——數(shù)據(jù)類,主要為各種AOP代理工廠提供屬性配置。

AdvisedSupport類是ProxyConfig類的子類,其封裝了AOP中對通知(Advice)和通知器(Advisor)的相關(guān)操作,這些操作對于不同的創(chuàng)建代理對象的類都是相同的,但是對于具體的AOP代理對象的生成需要AdvisedSupport各個(gè)子類去實(shí)現(xiàn)。

圖3-15 Spring AOP核心類圖

ProxyCreatorSupport類是AdvisedSupport的子類——輔助類,不同子類的一些通用的操作都封裝在ProxyCreatorSupport中。

ProxyFactoryBean,ProxyFactory和AspectJProxyFactory是用于創(chuàng)建AOP代理對象的,這三個(gè)類的作用分別如下:

? ProxyFactoryBean類:功能是創(chuàng)建聲明式的代理對象。

? ProxyFactory類:功能是創(chuàng)建編程式的代理對象。

? AspectJProxyFactory類:功能是創(chuàng)建基于AspectJ的代理對象。

3.6.1 設(shè)計(jì)原理

下面以ProxyFactoryBean為例,分析Spring AOP的實(shí)現(xiàn)原理。

首先定義一個(gè)接口Log,其中包含一個(gè)printLog()方法,Log接口的代碼如下:

再創(chuàng)建一個(gè)Target類,實(shí)現(xiàn)Log接口,重寫printLog方法,Target類的代碼如下:

然后創(chuàng)建一個(gè)通知類LogAroundAdvice并實(shí)現(xiàn)MethodInterceptor接口,重寫invoke()方法,在方法執(zhí)行前后分別打印實(shí)現(xiàn),LogAroundAdvice的實(shí)現(xiàn)如下:

創(chuàng)建一個(gè)測試類,用于觀察測試結(jié)果,測試代碼如下:

文件spring-chapter3-sourcecodelearning.xml的配置如下:

運(yùn)行測試代碼,測試結(jié)果如下:

     方法執(zhí)行開始時(shí)間:2018-10-03 08:18:51 167
     執(zhí)行一些操作
     方法執(zhí)行結(jié)束時(shí)間:2018-10-03 08:18:52 172

從測試結(jié)果可以看出,在正常的調(diào)用printLog()方法前后分別打印了日志,說明AOP已經(jīng)實(shí)現(xiàn)了。下面將通過這個(gè)案例分析ProxyFactoryBean的實(shí)現(xiàn)邏輯。

打開ProxyFactoryBean的代碼,其生成代理對象的核心方法是getObject()方法,部分代碼如下:

下面分析getObject()方法中的initializeAdvisorChain()方法,initializeAdvisorChain()方法是初始化通知器鏈(或者叫攔截器鏈)的,其代碼如下:

執(zhí)行initializeAdvisorChain()方法后,如果是單例模式,將會(huì)調(diào)用getSingletonInstance()方法獲取一個(gè)單例模式的代理對象,getSingletonInstance()方法代碼如下:

執(zhí)行initializeAdvisorChain()方法后,如果是非單例模式即原型模式,將會(huì)調(diào)用newPrototypeInstance()方法獲取一個(gè)新的原型模式的代理對象,newPrototypeInstance()方法代碼如下:

可以發(fā)現(xiàn),無論是單例模式還是原型模式,最終都是通過調(diào)用getProxy()方法獲取代理對象的,getProxy()的實(shí)現(xiàn)如下:

通過以上對getSingletonInstance()方法和newPrototypeInstance()方法的代碼注釋可以發(fā)現(xiàn),這兩個(gè)方法都會(huì)調(diào)用ProxyCreatorSupport.createAopProxy()方法,ProxyCreatorSupport類的核心代碼如下:

從createAopProxy()方法的代碼可以看出,AopProxy對象是在DefaultAopProxyFactory類的createAopProxy()方法中生成的,DefaultAopProxyFactory.createAopProxy()方法的代碼如下:

從DefaultAopProxyFactory.createAopProxy()使用的類的名稱可以發(fā)現(xiàn),如果是繼承了接口的類,會(huì)使用JDK動(dòng)態(tài)代理,即用JdkDynamicAopProxy類創(chuàng)建代理對象,否則將會(huì)使用CGLIB動(dòng)態(tài)代理即用ObjenesisCglibAopProxy類創(chuàng)建代理對象,關(guān)于這兩種動(dòng)態(tài)代理的具體使用,請參考本章3.1節(jié)。

3.6.2 JdkDynamicAopProxy

JDK動(dòng)態(tài)代理只能針對接口起作用,Spring中通過JdkDynamicAopProxy類使用JDK動(dòng)態(tài)代理創(chuàng)建AOPProxy對象,JdkDynamicAopProxy類的定義如下:

JdkDynamicAopProxy類實(shí)現(xiàn)了InvocationHandler接口,因而可以使用JDK動(dòng)態(tài)代理產(chǎn)生代理對象。

此處的getProxy()方法是獲取代理對象的入口,其是通過調(diào)用以下方法實(shí)現(xiàn)的:

findDefinedEqualsAndHashCodeMethods()方法的功能是查找代理的接口是否有定義equals()或hashCode()方法。

通過在3.1節(jié)中的介紹可以得知,InvocationHandler接口的invoke()方法是代理對象執(zhí)行方法調(diào)用和增強(qiáng)的地方,下面分析JdkDynamicAopProxy實(shí)現(xiàn)InvocationHandler接口重寫invoke()方法的代碼:

通過以上代碼分析可知,最核心的功能都是在invocation.proceed()方法中實(shí)現(xiàn)的,下面分析ReflectiveMethodInvocation,代碼如下:

invokeJoinpoint()方法是調(diào)用目標(biāo)對象方法的地方,其實(shí)現(xiàn)如下:

invokeJoinpoint()方法會(huì)調(diào)用AopUtils.invokeJoinpointUsingReflection()方法,代碼如下:

可以看到invokeJoinpointUsingReflection()方法最終是通過反射調(diào)用目標(biāo)對象的方法。

通過對JdkDynamicAopProxy類的代碼進(jìn)行分析可以知道,JdkDynamicAopProxy類實(shí)現(xiàn)了InvocationHandler接口,重寫了invoke()方法,當(dāng)進(jìn)行調(diào)用時(shí),其實(shí)并不是調(diào)用目標(biāo)對象,而是為目標(biāo)對象創(chuàng)建一個(gè)代理對象,觸發(fā)代理對象的invoke()方法,在invoke()方法中會(huì)通過反射調(diào)用目標(biāo)對象的方法,Spring AOP相關(guān)通知的調(diào)用也是在invoke()方法中完成的。

3.6.3 CglibAopProxy

由于JDK動(dòng)態(tài)代理只能針對接口生成代理對象,對于沒有實(shí)現(xiàn)接口的目標(biāo)對象,需要使用CGLIB產(chǎn)生代理對象,下面分析CglibAopProxy的代碼。

回到DefaultAopProxyFactory.createAopProxy()方法,如果目標(biāo)對象沒有實(shí)現(xiàn)接口,將會(huì)返回一個(gè)ObjenesisCglibAopProxy對象。ObjenesisCglibAopProxy類的代碼如下:

從代碼可以看出,ObjenesisCglibAopProxy繼承了CglibAopProxy,Objenesis是一個(gè)輕量級的Java庫,作用是繞過構(gòu)造器創(chuàng)建一個(gè)實(shí)例。因此分析的重點(diǎn)還是CglibAopProxy類。

由本章3.1節(jié)可知,CGLIB的運(yùn)行需要配合回調(diào)方法,實(shí)現(xiàn)MethodInterceptor接口,在CglibAopProxy中也是一樣,下面分析獲取回調(diào)方法getCallbacks()的代碼:

通過上面對CGLIB創(chuàng)建代理和獲取回調(diào)通知的代碼分析,可以了解到CGLIB在獲取代理通知時(shí),會(huì)創(chuàng)建DynamicAdvisedInterceptor類;當(dāng)調(diào)用目標(biāo)對象的方法時(shí),不是直接調(diào)用目標(biāo)對象,而是通過CGLIB創(chuàng)建的代理對象來調(diào)用目標(biāo)對象;并且在調(diào)用目標(biāo)對象的方法時(shí),會(huì)觸發(fā)DynamicAdvisedInterceptor的intercept回調(diào)方法對目標(biāo)對象進(jìn)行處理,CGLIB回調(diào)攔截器鏈的代碼如下:

這里的CglibMethodInvocation類繼承了ReflectiveMethodInvocation類,CglibMethodInvocation.procceed()調(diào)用了父類的ReflectiveMethodInvocation.proceed()方法,和3.6.2節(jié)中調(diào)用的方法是相同的,此處不再贅述。

主站蜘蛛池模板: 年辖:市辖区| 慈利县| 益阳市| 汉沽区| 岐山县| 临城县| 乌拉特中旗| 上蔡县| 措勤县| 师宗县| 喀什市| 关岭| 东乡族自治县| 汤原县| 玉环县| 宁津县| 政和县| 湄潭县| 广南县| 宜昌市| 沿河| 蓬莱市| 竹北市| 清涧县| 沅陵县| 桦甸市| 岳普湖县| 怀仁县| 阳东县| 买车| 罗定市| 廊坊市| 尼木县| 东莞市| 贺兰县| 镇巴县| 临潭县| 容城县| 水富县| 陈巴尔虎旗| 射洪县|