如果對(duì)spring的核心容器和JDK動(dòng)態(tài)代理官扣、CGLIB有所了解是复,接下來再看spring AOP源碼會(huì)比較容易懦傍。文中所有代碼片段截圖對(duì)應(yīng)的spring版本是5.0只锭。
本文內(nèi)容在頭條上也有發(fā)布:簡單粗暴看懂Spring AOP源碼
首先來看個(gè)問題鱼蝉,spring在哪里使用了AOP洒嗤?spring 實(shí)現(xiàn)AOP代碼的源頭在哪里葵硕?
spring AOP運(yùn)用動(dòng)態(tài)代理技術(shù)來創(chuàng)建和初始化代理對(duì)象茁肠。至于AOP代碼的源頭和入口,自然是和加載代理類的BeanDefinition和代理對(duì)象的創(chuàng)建纵顾、初始化有關(guān)。
1.spring AOP之加載和解析aop配置
先來看下加載BeanDefinition以及對(duì)aop配置的解析间唉,下面是從容器開始啟動(dòng)到解析BeanDefinitions的方法鏈:
然后我們直接定位到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions绞灼,如下圖:
上圖中parseCustomElement是對(duì)非節(jié)點(diǎn)的解析,相關(guān)的節(jié)點(diǎn)解析自然是走178行代碼分支呈野。該分支實(shí)際調(diào)用的是下圖中的代碼片段:
1361行代碼根據(jù)nameSpace匹配相應(yīng)的handler低矮,aop節(jié)點(diǎn)匹配的是右圖中的AopNamespaceHandler。1366行的parse調(diào)用的是其父類NamespaceHandlerSupport的parse方法被冒,如下圖:
節(jié)點(diǎn)匹配的則是圖中右側(cè)的ConfigBeanDefinitionParser军掂。來看下其實(shí)現(xiàn):
上述代碼106行配置了用于創(chuàng)建代理對(duì)象的AspectJAwareAdvisorAutoProxyCreator,我們看完aop配置解析之后再來分析昨悼。
節(jié)點(diǎn)的子節(jié)點(diǎn)是蝗锥,所以這里走118行的分支。然后就是對(duì)的子節(jié)點(diǎn),等的解析率触。
讀到這里應(yīng)該對(duì)AOP配置的解析有了大概的認(rèn)識(shí)终议。但是你是否想過,解析的結(jié)果封裝在哪里了葱蝗?是ParserContext穴张。
ConfigBeanDefinitionParser#parseAspect調(diào)用了ConfigBeanDefinitionParser#parseAdvice,來看下其實(shí)現(xiàn):
其中340行是最關(guān)鍵的两曼,可以看到最終是通過創(chuàng)建RootBeanDefinition來封裝我們aop節(jié)點(diǎn)的配置信息陆馁,然后在349行將beanDefinition注冊(cè)到容器(BeanFactory)。
aop配置的解析就看到這里合愈。下面來看aop中代理對(duì)象的創(chuàng)建、實(shí)例化等击狮。
2.spring AOP之創(chuàng)建代理
aop創(chuàng)建代理對(duì)象的時(shí)機(jī)是在調(diào)用getBean首次從容器中獲取bean時(shí)佛析。其實(shí)現(xiàn)
AbstractBeanFactory#getBean(java.lang.String)調(diào)用的是AbstractBeanFactory#doGetBean,下面來看該方法:
假設(shè)我們要獲取的bean是單例并且是首次獲取彪蓬,那么真正創(chuàng)建bean是調(diào)用的312行的createBean方法寸莫。至此,我們來看一下整個(gè)方法鏈:
下面來看下AbstractAutowireCapableBeanFactory#initializeBean:
其中紅線框起來的四個(gè)方法分別是:
invokeAwareMethods:調(diào)用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等
applyBeanPostProcessorsBeforeInitialization:調(diào)用BeanPostProcessor.postProcessBeforeInitialization
invokeInitMethods:調(diào)用InitializingBean#afterPropertiesSet,調(diào)用自定義initMethod
applyBeanPostProcessorsAfterInitialization:調(diào)用BeanPostProcessor#postProcessAfterInitialization
之前提到在解析aop配置時(shí)向容器注冊(cè)了AspectJAwareAdvisorAutoProxyCreator档冬,那么此處這個(gè)類要派上用場(chǎng)了膘茎。我們先來看下這個(gè)類的繼承體系:
從頂層看,該類主要包含三部分:
ProxyConfig即解析而來的aop配置
Aware部分主要是使其可訪問ClassLoader和BeanFactory
BeanPostProcessor則是bean初始化的前置和后置
上面出現(xiàn)的applyBeanPostProcessorsAfterInitialization調(diào)用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization酷誓,準(zhǔn)確地說是其繼承自父類的父類
AbstractAutoProxyCreator.postProcessAfterInitialization披坏。我們來看下該方法調(diào)用的
AbstractAutoProxyCreator#wrapIfNecessary,這也是spring判斷是否需要?jiǎng)?chuàng)建代理對(duì)象的地方:
該方法主要分三步:
352行判斷該接口或類或方法是否與配置的pointcut的表達(dá)式匹配盐数,匹配則需要?jiǎng)?chuàng)建代理對(duì)象棒拂,不匹配則無需代理。然后如果匹配則返回方法攔截器
355行創(chuàng)建代理對(duì)象
357行對(duì)代理類進(jìn)行緩存
我們重點(diǎn)看下createProxy方法實(shí)現(xiàn),方法鏈如下:
有了方法鏈之后我們直接跳到DefaultAopProxyFactory#createAopProxy帚屉,這個(gè)方法決定了spring aop動(dòng)態(tài)代理是使用CGLIB還是JDK Proxy:
解釋下51行if語句中的三個(gè)條件:
isOptimize表示讓spring自行優(yōu)化谜诫,默認(rèn)為false
isProxyTargetClass表示是否對(duì)類生成代理,默認(rèn)為false(即使用JDK Proxy,只代理接口)
第三個(gè)表示bean沒有實(shí)現(xiàn)任何接口或者實(shí)現(xiàn)的接口是SpringProxy接口
綜上攻旦,spring AOP默認(rèn)的創(chuàng)建代理的策略是:
對(duì)接口生成代理使用JDK Proxy
對(duì)類生成代理使用CGLIB
可通過proxyTargetClass配置是否對(duì)類生成代理喻旷,為true表示對(duì)類生成代理,為false表示不會(huì)對(duì)類(沒有實(shí)現(xiàn)SpringProxy以外的接口的類)生成代理
如果覺得寫的不錯(cuò)牢屋,記得點(diǎn)擊關(guān)注且预,如果寫的不好歡迎批評(píng)指正,讓我們一起進(jìn)步伟阔!