不管是採用 XML 仍是註解方式,最終 Spring 讀取加載後都會生成與之對應的 BeanDefinition,而後利用它就能夠去實例化一個對象。java
BeanDefinition 用來描述建立一個實例所須要的信息express
簡單的看來建立一個對象其實就 2 步驟緩存
Spring 就在這幾個步驟中穿插邏輯,從而拓展出了一個生態,下面咱們就來看看 AOP 的實現原理app
基本用法這裏就再也不贅述框架
在 new AnnotationConfigApplicationContext(Class<?>... componentClasses)
首先將 AppConfig
解析爲 BeanDefinition
放入 BeanFactory
的 BeanDefinitionMap
中post
而後調用 refresh()
方法中,會調用 invokeBeanFactoryPostProcessors(beanFactory);
在這個方法中去調用全部的 BeanFactoryProcessor
spa
那麼什麼是 BeanFactoryProcessor
它又有什麼做用呢?看下面這段代碼代理
經過實現了 BeanFactoryProcessor
咱們能夠拿到 ConfigurableListableBeanFactory
,經過容器咱們就能拿到 BeanDefinition
進行分析和修改,從而間接的影響 Bean 的實例化作到咱們無感知,無侵入的加強和拓展類的功能code
而後該方法中,會繼續調用 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
(還調用了其它的方法,本文只討論這個方法),BeanDefinitionRegistryPostProcessor
它的做用是能夠像容器中添加新的 BeanDefinition
,在這一步將解析 JavaConfig
對應的 BeanDefinition
,而後解析 @ComponentScan(basePackages = "com.example.ana")
這個註解,將這個包下面的全部類,裝載爲 BeanDefinition
而後放入 BeanFactory
容器中component
到此爲止,包下面的全部類就已經掃描裝載完畢在 BeanFactory
的 BeanDefinitionMap
中
要想應用 advice 邏輯,首先咱們須要找到對應的切面,而後咱們在其中查看須要在哪些方法中織入對應的 advice 邏輯,好比在 UserServiceImpl
的 queryUser
這個 JoinPoint
切點以後織入 afterQuery
這分爲 2 步,先來看是如何查找切面 @Aspect
的,從 refresh()
中看起走,到這個位置
在 createBean 中調用了 resolveBeforeInstantiation
這個方法,目的就是給 BeanPostProcessor
一個返回代理對象的機會,好比下圖將全部 beanName 名字爲 a 的對象替換成對象 C
它有它的做用好比
咱們這裏是爲了尋找對應的 @Aspect
接着往下看,獲取全部的 BeanPostProcessor
須要注意的是除去咱們本身定義的 BeanPostProcessor
以外還有框架自身的一些實現類,而後若是發現類是 InstantiationAwareBeanPostProcessor
的話
@Aspect
這個註解advice
的相關信息緩存到 advisorsCache
中首次調用 BeanPostProcessor
的實現就會作以上這件事,後續的調用就直接從緩存中取用便可
如今全部的 @Aspect
都已經緩存好了,如今就要知道如何在調動業務邏輯的時候,如何織入對應的 advice 邏輯,好比在調用一個事務方法的時候,系統是怎麼幫我作到,自動打開事務,方法結束的時候提交事務的,這就須要一個代理對象幫我去作這件事情,那麼何時該建立代理對象,代理對象又是如何執行對應的 advice 方法呢
舉個很簡單的例子
User user = new User("小李");
user.getName();
複製代碼
這裏就只有一個獲取名稱的方法,其它什麼都不須要,那你說還須要爲它建立代理對象嗎,確定不須要,再看下面這個
@Transactional
public void saveXXX() {
xxxDao.saveUser();
xxxDao.saveProject();
}
複製代碼
這個方法咱們添加了事務,要求只要其中一個失敗就得進行回滾從而保證這個操做是一個原子操做,這個方法確定就須要建立代理對象了
就這個例子來看,當咱們發現所調用方法的註解具備必定的邏輯功能的話就須要建立代理對象,拓展來看就是說,咱們須要判斷一個類,或者類中是否存在某個方法須要被加強處理,從而來決定是否建立代理對象
那麼在咱們這個例子中,在實例化每一個對象的時候,就是首先從 advisorsCache
取出 advisor
檢測當前類是否知足 pointcut
的 expression
條件,知足的話就須要爲其建立代理對象,而且將匹配到的 advisor 存入代理對象中,最後容器中最後的實現類也變成了對應的代理類
1) 早期 bean 對象的建立
在 resolveBeforeInstantiation
方法後就會調用 doCreateBean
來建立實例,在這裏面首先會建立一個早期 bean 對象,這個對象主要是用於解決循環依賴問題,好比
class A {
B b;
}
class B {
A a;
}
複製代碼
他們都是單例,Spring 在實例化 A 的時候,發現依賴了 B 須要去實例化 B,在實例化 B 的時候又發現須要實例化 A,形成循環依賴沒法實例化成功
Spring 解決這個問題的核心思想很是簡單,就是先建立一個早期 A 對象,僅僅是一個沒有填充屬性的引用,而後去建立 B 對象的時候再填充 A 就成功了,方法遞歸返回 A 對象也就建立成功了,容器已經持有了對應的引用,那麼在後續填充完各自的屬性後就算建立完整了
2)填充 Bean 的相關屬性
上一步操做獲得了一個早期的 bean 對象,而且放入了早期容器中下一步就是調用 populateBean
對 bean 的屬性就行填充,主要作如下 2 件事情
3)初始化 Bean
若是類實現了 InitializingBean
接口,就調用它的 afterPropertiesSet
進行值的設置
若是 XML 定義了 init-method 的話後續就會調用 invokeCustomInitMethod
,而後調用對應的初始化方法進行初始化
4)建立代理實例
在初始化 Bean 完成後就會調用 applyBeanPostProcessorsAfterInitialization
,旨在初始化完成後再給與一次修改 Bean 的機會
在這個方法中會去獲取全部的 BeanPostProcessor
而後依次調用其 postProcessAfterInitialization
方法
除去咱們本身實現了 BeanPostProcessor
以外,框架自己還提供了不少用於自身使用,這些 Processor 會在 refresh()
中的 registerBeanPostProcessors
方法中進行註冊和排序
其中有一個是 AbstractAutoProxyCreator
的實現,調用它的 postProcessAfterInitialization
裏面會調用 wrapIfNecessary
,這個方法首先它會去找到全部候選的 advisor
,而後判斷當前類或者實例中的方法,是否知足 @PointCut
的表達式,將成功匹配到的 advisor
返回
advisor
設置進去
到此爲止一個完整的代理對象就建立完畢
advice
方法做爲一個調用鏈 chain
CglibMethodInvocation
而後調用 proceed
advice
方法和執行被代理的目標方法總的來講就分爲 2 步驟