輕輕鬆鬆看懂Spring AOP源碼
如果對spring的核心容器和JDK動態代理、CGLIB有所了解,接下來再看spring AOP源碼會比較容易。文中所有代碼片段截圖對應的spring版本是5.0。
本文內容曾首發於頭條。
首先來看個問題,spring在哪裡使用了AOP?spring 實現AOP代碼的源頭在哪裡?
spring AOP運用動態代理技術來創建和初始化代理對象。至於AOP代碼的源頭和入口,自然是和載入代理類的BeanDefinition和代理對象的創建、初始化有關。
1.spring AOP之載入和解析aop配置
先來看下載入BeanDefinition以及對aop配置的解析,下面是從容器開始啟動到解析BeanDefinitions的方法鏈:
然後我們直接定位到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,如下圖:
上圖中parseCustomElement是對非節點的解析,相關的節點解析自然是走178行代碼分支。該分支實際調用的是下圖中的代碼片段:
1361行代碼根據nameSpace匹配相應的handler,aop節點匹配的是右圖中的AopNamespaceHandler。1366行的parse調用的是其父類NamespaceHandlerSupport的parse方法,如下圖:
節點匹配的則是圖中右側的ConfigBeanDefinitionParser。來看下其實現:
上述代碼106行配置了用於創建代理對象的AspectJAwareAdvisorAutoProxyCreator,我們看完aop配置解析之後再來分析。
節點的子節點是,所以這裡走118行的分支。然後就是對的子節點,等的解析。
讀到這裡應該對AOP配置的解析有了大概的認識。但是你是否想過,解析的結果封裝在哪裡了?是ParserContext。
ConfigBeanDefinitionParser#parseAspect調用了ConfigBeanDefinitionParser#parseAdvice,來看下其實現:
其中340行是最關鍵的,可以看到最終是通過創建RootBeanDefinition來封裝我們aop節點的配置信息,然後在349行將beanDefinition註冊到容器(BeanFactory)。
aop配置的解析就看到這裡。下面來看aop中代理對象的創建、實例化等。
2.spring AOP之創建代理
aop創建代理對象的時機是在調用getBean首次從容器中獲取bean時。其實現
AbstractBeanFactory#getBean(java.lang.String)調用的是AbstractBeanFactory#doGetBean,下面來看該方法:
假設我們要獲取的bean是單例並且是首次獲取,那麼真正創建bean是調用的312行的createBean方法。至此,我們來看一下整個方法鏈:
下面來看下AbstractAutowireCapableBeanFactory#initializeBean:
其中紅線框起來的四個方法分別是:
invokeAwareMethods:調用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等
applyBeanPostProcessorsBeforeInitialization:調用BeanPostProcessor.postProcessBeforeInitialization
invokeInitMethods:調用InitializingBean#afterPropertiesSet,調用自定義initMethod
applyBeanPostProcessorsAfterInitialization:調用BeanPostProcessor#postProcessAfterInitialization
之前提到在解析aop配置時向容器註冊了AspectJAwareAdvisorAutoProxyCreator,那麼此處這個類要派上用場了。我們先來看下這個類的繼承體系:
從頂層看,該類主要包含三部分:
ProxyConfig即解析而來的aop配置
Aware部分主要是使其可訪問ClassLoader和BeanFactory
BeanPostProcessor則是bean初始化的前置和後置
上面出現的applyBeanPostProcessorsAfterInitialization調用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization,準確地說是其繼承自父類的父類
AbstractAutoProxyCreator.postProcessAfterInitialization。我們來看下該方法調用的
AbstractAutoProxyCreator#wrapIfNecessary,這也是spring判斷是否需要創建代理對象的地方:
該方法主要分三步:
352行判斷該介面或類或方法是否與配置的pointcut的表達式匹配,匹配則需要創建代理對象,不匹配則無需代理。然後如果匹配則返回方法攔截器
355行創建代理對象
357行對代理類進行緩存
我們重點看下createProxy方法實現,方法鏈如下:
有了方法鏈之後我們直接跳到DefaultAopProxyFactory#createAopProxy,這個方法決定了spring aop動態代理是使用CGLIB還是JDK Proxy:
解釋下51行if語句中的三個條件:
isOptimize表示讓spring自行優化,默認為false
isProxyTargetClass表示是否對類生成代理,默認為false(即使用JDK Proxy,只代理介面)
第三個表示bean沒有實現任何介面或者實現的介面是SpringProxy介面
綜上,spring AOP默認的創建代理的策略是:
對介面生成代理使用JDK Proxy
對類生成代理使用CGLIB
可通過proxyTargetClass配置是否對類生成代理,為true表示對類生成代理,為false表示不會對類(沒有實現SpringProxy以外的介面的類)生成代理


TAG:明哥JAVA指南 |