spring Aop實現原理(原始碼)
前文《spring Aop前傳》講解了Aop程式設計正規化的來歷與工作原理,接下來將會介紹spring Aop作為一個aop的實現。在介紹spring Aop底層工作方式之前,我們拋開spring Aop真正實現,基於當前對spring的認識做一個大膽的假設,在ioc容器中,所有的物件都是bean,spring aop要做的就是將公共模組呼叫填充到制定bean裡面,那麼spring aop是在bean已經初始化完成,直接在bean中新增公共模組呼叫呢?還是依照bean的型別生成代理物件,然後代理物件的對應接口裡面呼叫公共模組和bean物件的對應方法呢?第一種假設應該不太可能,因為bean例項化之後,對映的是一個記憶體塊存放指令;那麼就是使用第二種方式,首先使用位元組碼技術對bean的具體實現生成代理(生成的java位元組碼載入進jvm初始化後),然後在要增強的型別對應介面增加公共模組和bean對應方法呼叫。那麼帶著假設和疑問一起探索spring
aop底層實現。
spring aop相關的元資料(集中化的呼叫位置資訊與公共模組資訊等)與其他spring應用元資料一樣,可使用兩種方式進行配置——基於xml和java註解,這兩種元資料儲存方式各有利弊,官方都說不清最優方案是哪個,xml可以將配置元資料集中在一個或幾個檔案,而annotation是偏向分散的,但是不需要了解和學習xml相關知識,它是java技術一部分,這章節不是討論元資料儲存與讀取方案優劣的,所以元資料處理就暫時打住。這裡的元資料以xml儲存為例進行探討spring aop底層工作流程。spring框架在初始化的時候第一個步驟就是讀取元資料,第二步就是將讀取到的元資料解析成spring框架抽象資料表示,在spring框架中,核心資料抽象表示是beanDefinition,主要是因為面向物件程式是有型別的例項物件組成的,一個beanDefintion就是一個物件的定義。spring aop主元資料配置也將會被解析成beanDefinition,但spring aop定義的bean不是普通的bean,它是一個實現BeanPostProcessor介面的AspectJAwareAdvisorAutoProxyCreator實現。BeanPostProcessor是ioc容器用於處理bean的回撥介面,通過這個回撥介面你可以自定義bean的特性,spring aop正正是利用這一個介面的postProcessAfterInitialization回撥將已經注入依賴的bean包裝到使用Cglib生成的代理裡面去的。spring框架初始化的第三步是將spring aop定義註冊到ioc容器裡面去,這部分的定義將會將例項化advisor註冊到bean postprocessor,以備ioc容器例項化並將依賴注入bean之後呼叫postProcessor,postProcessor會利用postProcessor裡面的advisor的pointcut Expression,檢查是否屬於aop橫切的範圍。如果在spring aop橫切範圍,那麼呼叫createProxy方法,引數包括已經初始化的bean,這個方法將會建立ProxyFactory例項,ProxyFactory例項對於介面使用java代理(預設,不設定所有使用Cglib代理),對於類使用Cglib的Enhancer生成代理。第四步,ioc容器將 bean postProcessor返回的包裝bean(實則cglib根據類生成的代理物件)與beanName註冊到ioc容器去,最終開發者拿到的bean通過beanName從ioc容器拿到的bean就是已經處理過的代理物件了。
最後由於spring aop與spring ioc處理過程緊密相連,附上spring ioc初始化過程、spring aop實現過程時序圖,並加以簡單解釋。
圖1顯示的是spring ioc容器初始化的關鍵步驟):
1)refresh方法是初始化ioc容器的入口。2)refreshBeanFactory方法用於載入、解析和註冊應用元資料到ioc容器。3)prepareBeanFactory方法配置工程餓標準上下文特性,例如classLoader和postprocessor。4)postProcessBeanFactory註冊request/session scope。5)invokeBeanFactoryPostProcessors例項化並呼叫所有註冊的BeanFactoryPostProcessor。6)registerBeanPostProcessors例項化並呼叫所有BeanPostProcessor。7)initApplicationEventMulticaster初始化ApplicationEventMulticaster。8)registerListeners新增實現AppicationListener的bean為listener。9)finishBeanFactoryInitialization完成當前context的bean factory,初始化所有singleton bean,這一步是集中例項化bean的統一入口。10)finishRefresh完成更新context,呼叫LifecycleProcessor的onRefresh方法,併發布ContextRefreshedEvent事件。從上面的步驟中,可以看出需要先初始化bean post processor(也是初始化成bean),然後才進行singleton 的bean的例項化,這是由於bean post processor是例項化bean的回撥介面。
圖2顯示的是singleton 的bean的初始化過程,主要有幾個重要的方法,首先是getBean方法,這個方法是ioc容器對外提供的統一獲取bean介面,該介面會先從已經例項化裡面獲取,存在就不再例項化bean,不存在就獲取beanDefinition進行例項化也依賴注入;其次是populateBean方法,這個方法是進行依賴注入的,在進行依賴注入的時候呼叫getBean方法獲取依賴,依賴沒有初始化並註冊的就進行初始化,它會呼叫applyPropertyValues方法設定成員域的值(依賴);最後就是aop的處理入口——initializeBean,到了這一步已經將bean例項化並將依賴注入進行,這個方法將會呼叫applyBeanPostProcessorsAfterInitialization方法,它將會遍歷ioc容器的BeanPost Processor,其中就有我們的AspectJAwareAdvisorAutoProxyCreator,這個BeanPostProcessor將會將已經檢查初始化的bean是否在定義好的pointcut範圍,在的話就會以初始化好的bean為targetSource生成代理物件,也就是說initializeBean方法返回的是一個包裝bean,然後將這個包裝bean與beanName註冊到ioc容器上面去,這樣使用beanName獲取的bean就是代理物件了。
圖3是spring aop建立代理的過程,對於類,底層使用cglib來建立代理。