AOP是什么怎么用就不在這里贅述了,這里就從源碼看一下AOP的實(shí)現(xiàn)启妹。
1、Spring 如果要支持注解形式的AOP,就要在配置文件中配置<aop:aspectj-autoproxy/>啄清。
這里簡(jiǎn)單說(shuō)一下Spring解析標(biāo)簽的過(guò)程:Spring中將標(biāo)簽分為默認(rèn)標(biāo)簽(import、alias,bean和beans)和自定義標(biāo)簽俺孙。
<aop:aspectj-autoproxy/>屬于自定義標(biāo)簽盒延,解析過(guò)程為當(dāng)讀取到這個(gè)標(biāo)簽時(shí),會(huì)根據(jù)命名空間去找到對(duì)應(yīng)的自定義標(biāo)簽處理器AopNamespaceHandler鼠冕,AopNamespaceHandler會(huì)執(zhí)行init()方法添寺。在這里會(huì)將AspectJAutoProxyBeanDefinitionParser進(jìn)行注冊(cè)。而AspectJAutoProxyBeanDefinitionParser正是專門解析"aspectj-autoproxy"標(biāo)簽的解析器懈费。
AspectJAutoProxyBeanDefinitionParser實(shí)現(xiàn)了BeanDefinitionParser接口计露,會(huì)執(zhí)行parse()對(duì)標(biāo)簽進(jìn)行解析。這個(gè)parse()中AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element)這個(gè)方法憎乙,從名字就可以看出是用來(lái)注冊(cè)自動(dòng)代理創(chuàng)建器票罐,我們具體看下這個(gè)方法內(nèi)做了什么。
一共做了三件事:
????1)注冊(cè)或者升級(jí)AnnotationAwareAspectJAutoProxyCreator
? ? 2)對(duì)于proxy-target-class以及expose-proxy 屬性的處理
? ? 3)注冊(cè)組件并通知泞边,便于監(jiān)聽(tīng)器做進(jìn)一步處理
1)注冊(cè)或者升級(jí)AnnotationAwareAspectJAutoProxyCreator
? ?先看第一件该押,跟蹤代碼可依次走到如下兩個(gè)方法。主要功能點(diǎn)就是注冊(cè)AnnotationAwareAspectJAutoProxyCreator阵谚。
? ?具體注冊(cè)過(guò)程蚕礼,會(huì)先判斷自動(dòng)代理創(chuàng)建器是否已經(jīng)存在。
????? ? 1)不存在梢什,直接創(chuàng)建新的創(chuàng)建器奠蹬。
????? ? 2)若存在
? ? ? ????? ? ? 1)且與想要?jiǎng)?chuàng)建的新創(chuàng)建器相同,不進(jìn)行操作嗡午。
? ? ? ????? ? ? 2)且與想要?jiǎng)?chuàng)建的新創(chuàng)建器不同囤躁,就要判斷兩個(gè)創(chuàng)建器的優(yōu)先級(jí),如果新創(chuàng)建器優(yōu)先級(jí)高,則進(jìn)行新創(chuàng)建器的創(chuàng)建狸演,否則不操作還是用原來(lái)創(chuàng)建器言蛇。
?2)對(duì)于proxy-target-class以及expose-proxy 屬性的處理
? ? ?這個(gè)方法實(shí)際就是讀取配置文件并將屬性賦值的過(guò)程。
????????說(shuō)一下這個(gè)兩個(gè)屬性作用宵距。
?????? ????1)proxy-target-class
? ? ? ? ????默認(rèn)情況下猜极,"proxy-target-class"默認(rèn)是"false",當(dāng)被代理類實(shí)現(xiàn)了至少一個(gè)接口消玄,Spring默認(rèn)使用JDK動(dòng)態(tài)代理跟伏,當(dāng)被代理類沒(méi)有實(shí)現(xiàn)接口時(shí)使用CGLIB代理,但是如果想強(qiáng)制任何時(shí)候都使用CGLIB代理翩瓜,那么需要如下配置:
????????????????????????????????<aop : aspectj-autoproxy????proxy-target-class="true"/>
? ? ? ? ????2)expose-proxy
? ? ? ? ?如下例子可以說(shuō)明這個(gè)屬性受扳。
有時(shí)候目標(biāo)對(duì)象內(nèi)部的自我調(diào)用將無(wú)法實(shí)施切面中的增強(qiáng),此處的this 指向目標(biāo)對(duì)象兔跌,因此調(diào)用this.b()將不會(huì)執(zhí)行b事務(wù)切面勘高,即不會(huì)執(zhí)行事務(wù)增強(qiáng)。
為了解決這個(gè)問(wèn)題坟桅,配置:
<aop:aspectj-autoproxy expose-proxy=”true”/>
然后將以上代碼中的“this.b()”修改為“ ((AService) AopContext.currentProxy()).b()”即可华望。
通過(guò)以上的修改便可以完成對(duì)a和b方法的同時(shí)增強(qiáng)。
?3)注冊(cè)組件并通知仅乓,便于監(jiān)聽(tīng)器做進(jìn)一步處理
? ? 這一步是注冊(cè)組件赖舟,對(duì)于AOP實(shí)現(xiàn)沒(méi)有什么關(guān)聯(lián)。
2夸楣、在上面完成了AnnotationAwareAspectJAutoProxyCreator的注冊(cè)創(chuàng)建宾抓,這個(gè)類也是實(shí)現(xiàn)AOP的關(guān)鍵,我們看這個(gè)類到底怎么實(shí)現(xiàn)的AOP豫喧∈矗可以看到AnnotationAwareAspectJAutoProxyCreator類實(shí)現(xiàn)了BeanPostProcessor接口。
BeanPostProcessor常常被稱為后置處理器紧显,作用是在Bean對(duì)象在實(shí)例化和依賴注入完畢后讲衫,在顯示調(diào)用初始化方法的前后添加我們自己的邏輯。流程如下:
Spring IOC容器實(shí)例化Bean--->調(diào)用BeanPostProcessor的postProcessBeforeInitialization方法--->調(diào)用bean實(shí)例的初始化方法--->調(diào)用BeanPostProcessor的postProcessAfterInitialization方法
AnnotationAwareAspectJAutoProxyCreator實(shí)現(xiàn)BeanPostProcessor 后孵班,當(dāng)Spring加載Bean時(shí)會(huì)在初始化后調(diào)用其父類AbstractAutoProxyCreator重寫的postProcessAfterInitialization方法涉兽,對(duì)生產(chǎn)出的bean進(jìn)行包裝。
具體看下AbstractAutoProxyCreator重寫的postProcessAfterInitialization方法重父,其中wrapIfNecessary()方法是我們要關(guān)注的花椭。
看注釋相信大家也大概明白這個(gè)方法的邏輯了,無(wú)非是先判斷這個(gè)類是不是需要增強(qiáng)房午,如果需要增強(qiáng)就創(chuàng)建代理。這里我們主要看getAdvicesAndAdvisorsForBean()和createProxy()這兩個(gè)方法丹允。
1)getAdvicesAndAdvisorsForBean()
下面實(shí)際做了兩件事郭厌,獲取所有的增強(qiáng)器以及尋找所有增強(qiáng)器中適用于這個(gè)bean 的增強(qiáng)器袋倔。
我們先來(lái)看一下怎么獲取的所有增強(qiáng)器。主要是分別獲取了xml配置中的增強(qiáng)器和注解中的增強(qiáng)器折柠。
我們主要看一下怎樣獲取注解形式的增強(qiáng)器宾娜,也就是buildAspectJAdvisors()這個(gè)方法,圖片里有注釋扇售,簡(jiǎn)單來(lái)說(shuō)就是拿到所有beanName前塔,遍歷beanName找到有@Aspect注解的類,然后處理這些有@Aspect注解的類的提取增強(qiáng)器承冰。
提取增強(qiáng)器主要是getAdvisors()這個(gè)方法华弓,我們接下來(lái)看下這個(gè)方法具體實(shí)現(xiàn)。
1)getPointcut()拿到切點(diǎn)信息
2)new InstantiationModelAwarePointcutAdvisorImpl()封裝生成增強(qiáng)器困乒。
1)getPointcut()拿到切點(diǎn)信息
切點(diǎn)信息獲取其實(shí)也是獲取方法上注解的信息寂屏,不詳細(xì)解釋了。
2)new InstantiationModelAwarePointcutAdvisorImpl()封裝生成增強(qiáng)器娜搂。
可以看出來(lái)如果是懶加載迁霎,則先看到這可能還是不能看出來(lái)我們熟悉的內(nèi)容,別急百宇,往下看考廉,看instantiateAdvice()方法。
我們可以看到before携御、after這些我們熟悉的切面注解了芝此,spring會(huì)根據(jù)注解生成不同類型的增強(qiáng)器,常說(shuō)的前置增強(qiáng)因痛、后置增強(qiáng)婚苹、環(huán)繞增強(qiáng)。
至此我么我們知道了spring怎么獲取所有的增強(qiáng)器鸵膏。那么返回之前我們的地方膊升。拿到所有增強(qiáng)器后,就是找出適用這個(gè)bean的增強(qiáng)器谭企,其實(shí)就是找到符合我們配置的通配符的增強(qiáng)器廓译。
至此我們分析完了獲取這個(gè)類增強(qiáng)器的方法。如果這個(gè)類存在需要增強(qiáng)器债查,就要?jiǎng)?chuàng)建代理非区,也就是createProxy()。
這個(gè)方法就為我們創(chuàng)建了代理類,當(dāng)實(shí)際調(diào)用時(shí)是代理類替代目標(biāo)類為我們執(zhí)行了方法盹廷,當(dāng)然就把我們的切面方法也執(zhí)行了征绸。
BeanPostProcessor