死磕Spring之AOP篇 – Spring AOP自動代理(一)入口
- 2021 年 4 月 19 日
- 筆記
- Spring AOP, 死磕Spring之AOP篇, 源碼解析
該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀。
Spring 版本:5.1.14.RELEASE
在開始閱讀 Spring AOP 源碼之前,需要對 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 – 文章導讀》 這一系列文章
了解 AOP 相關術語,可先查看 《Spring AOP 常見面試題) 》 這篇文章
該系列其他文章請查看:《死磕 Spring 之 AOP 篇 – 文章導讀》
通過上一篇文章《Spring AOP 總覽》我們對 Spring AOP 有了一個整體的認識,那麼從本篇文章開始,我們一起來看看 Spring AOP 和 Spring IoC 是如何整合的,自動代理的過程做了哪些事情?
首先我們得清楚 Bean 的載入過程,整個過程中會調用相應的 BeanPostProcessor 對正在創建 Bean 進行處理,例如:
-
在 Bean 的實例化前,會調用
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(..)
方法進行處理 -
在 Bean 出現循環依賴的情況下,會調用
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..)
方法對提前暴露的 Bean 進行處理 -
在 Bean 初始化後,會調用
BeanPostProcessor#postProcessAfterInitialization(..)
方法對初始化好的 Bean 進行處理
Spring AOP 則是通過上面三個切入點進行創建代理對象,實現自動代理。
- 在 Spring AOP 中主要是通過第
3
種 BeanPostProcessor 創建代理對象,在 Bean 初始化後,也就是一個「成熟態」,然後再嘗試是否創建一個代理對象; - 第
2
種方式是為了解決 Bean 循環依賴的問題,雖然 Bean 僅實例化還未初始化,但是出現了循環依賴,不得不在此時創建一個代理對象; - 第
1
種方式是在 Bean 還沒有實例化的時候就提前創建一個代理對象(創建了則不會繼續後續的 Bean 的創建過程),例如 RPC 遠程調用的實現,因為本地類沒有遠程能力,可以通過這種方式進行攔截。
對於 Bean 的載入過程不清楚的小夥伴可以查看我的《死磕Spring之IoC篇 – 文章導讀》這篇文章,或者直接查看《死磕Spring之IoC篇 – Bean 的創建過程》 這篇文章
Spring AOP 自動代理的實現主要由 AbstractAutoProxyCreator
完成,它實現了 BeanPostProcessor、SmartInstantiationAwareBeanPostProcessor 和 InstantiationAwareBeanPostProcessor 三個介面,那麼這個類就是 Spring AOP 的入口,在這裡將 Advice 織入我們的 Bean 中,創建代理對象。
如何激活 AOP 模組?
如何開啟 Spring 的 AOP 模組,首先我們需要引入 spring-aop
和 aspectjweaver
兩個模組,然後通過下面的方式開啟 AOP:
- 添加
@EnableAspectJAutoProxy
註解 - 添加
<aop:aspectj-autoproxy />
XML 配置
備註:在 Spring Boot 中使用 AOP 可以不需要上面兩種配置,因為在 Spring Boot 中當你引入上面兩個模組後,默認開啟,可以看到下面這個配置類:
package org.springframework.boot.autoconfigure.aop;
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {}
}
只要存在 EnableAspectJAutoProxy
、Aspect
、Advice
、AnnotatedElement
四個 Class 對象,且 spring.aop.auto
配置為 true
(沒有配置則為 true
),那麼就會載入 AopAutoConfiguration 當前這個 Bean,而內部又使用了 @EnableAspectJAutoProxy
註解,那麼表示開啟 AOP。
至於這個註解或者 XML 配置的方式為什麼就開啟 AOP,是因為會引入 AbstractAutoProxyCreator
這個對象,具體怎麼引入的,在後續文章進行分析😈
類圖
簡單描述:
- 【重點】
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
:AOP 自動代理的抽象類,完成主要的邏輯實現,提供一些骨架方法交由子類完成 org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
:僅支援指定List<String> beanNames
完成自動代理,需要指定interceptorNames
攔截器- 【重點】
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
:支援從當前 Spring 上下文獲取所有 Advisor 對象,存在能應用與 Bean 的 Advisor 則創建代理對象 org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
:僅支援獲取 Spring 內部的 Advisor 對象(BeanDefinition 的角色為 ROLE_INFRASTRUCTURE)org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
:支援配置前綴,只能獲取名稱已該前綴開頭的 Advisor 對象- 【重點】
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator
:支援按照 AspectJ 的方式對 Advisor 進行排序 - 【重點】
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
:支援從帶有@AspectJ
註解 Bean 中解析 Advisor 對象
我們主要關註上面【重點】的幾個對象,因為 Sping AOP 推薦使用 AspectJ 裡面的註解進行 AOP 的配置,你牢牢記住AbstractAutoProxyCreator這個自動代理類。
AbstractAutoProxyCreator
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
:AOP 自動代理的抽象類,完成主要的邏輯實現,提供一些骨架方法交由子類完成
相關屬性
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/** 空對象,表示不需要進行代理 */
@Nullable
protected static final Object[] DO_NOT_PROXY = null;
/**
* 空的數組,表示需要進行代理,但是沒有解析出 Advice
* 查看 {@link BeanNameAutoProxyCreator#getAdvicesAndAdvisorsForBean} 就知道其用途
*/
protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0];
/** DefaultAdvisorAdapterRegistry 單例,Advisor適配器註冊中心 */
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
/** 是否凍結代理對象 */
private boolean freezeProxy = false;
/** 公共的攔截器對象 */
private String[] interceptorNames = new String[0];
/** 是否將 `interceptorNames` 攔截器放在最前面 */
private boolean applyCommonInterceptorsFirst = true;
/** 自定義的 TargetSource 創建器 */
@Nullable
private TargetSourceCreator[] customTargetSourceCreators;
@Nullable
private BeanFactory beanFactory;
/**
* 保存自定義 {@link TargetSource} 對象的 Bean 的名稱
*/
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
* 保存提前創建代理對象的 Bean
* key:cacheKey(Bean 的名稱或者 Class 對象)
* value:Bean 對象
*
* Spring AOP 的設計之初是讓 Bean 在完全創建好後才完成 AOP 代理,如果出現了循環依賴,則需要提前(實例化後還未初始化)創建代理對象
* 那麼需要先保存提前創建代理對象的 Bean,這樣在後面可以防止再次創建代理對象
*/
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
/**
* 保存代理對象的 Class 對象
* key:cacheKey(Bean 的名稱或者 Class 對象)
* value:代理對象的 Class 對象(目標類的子類)
*
*/
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
/**
* 保存是否需要創建代理對象的資訊
* key:cacheKey(Bean 的名稱或者 Class 對象)
* value:是否需要創建代理對象,false 表示不需要創建代理對象,true 表示已創建代理對象
*/
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
}
上面的每個屬性都已經注釋,先簡單理解即可,具體在後面的方法可查看其用途
getEarlyBeanReference 方法
getEarlyBeanReference(Object bean, String beanName)
,用於處理早期暴露的對象,如果有必要的話會創建一個代理對象,該方法定義在 SmartInstantiationAwareBeanPostProcessor 中,實現如下:
/**
* 該方法對早期對象(提前暴露的對象,已實例化還未初始化)進行處理
* 參考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference }
*
* @param bean the raw bean instance
* @param beanName the name of the bean
* @return 早期對象(可能是一個代理對象)
*/
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// <1> 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
Object cacheKey = getCacheKey(bean.getClass(), beanName);
/*
* <2> 將當前 Bean 保存至 earlyProxyReferences 集合(早期的代理應用對象)
* 也就是說當這個 Bean 出現循環依賴了,在實例化後就創建了代理對象(如果有必要)
*/
this.earlyProxyReferences.put(cacheKey, bean);
// <3> 為這個 Bean 創建代理對象(如果有必要的話)
return wrapIfNecessary(bean, beanName, cacheKey);
}
該方法的處理過程如下:
- 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
- 將當前 Bean 保存至
earlyProxyReferences
集合(早期的代理應用對象),也就是說當這個 Bean 出現循環依賴了,在實例化後就創建了代理對象(如果有必要),可以防止後續初始化後再次創建代理對象 - 【重點】調用
wrapIfNecessary(..)
方法,為這個 Bean 創建代理對象(如果有必要的話),該方法在後面分析👨🎓
對於 getEarlyBeanReference(..)
方法在哪被調用,可能你已經忘記了,這裡來回顧一下:
// 在 AbstractAutowireCapableBeanFactory#doCreateBean 創建 Bean 的過程中,實例化後會執行下面步驟
/**
* <3.2>
* 創建一個 ObjectFactory 實現類,用於返回當前正在被創建的 `bean`,提前暴露,保存在 `singletonFactories` (**三級 Map**)快取中
*
* 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
* 載入 Bean 的過程會先從快取中獲取單例 Bean,可以避免單例模式 Bean 循環依賴注入的問題
*/
addSingletonFactory(beanName,
// ObjectFactory 實現類
() -> getEarlyBeanReference(beanName, mbd, bean));
// 獲取早期暴露的對象時候的處理,會調用 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() // RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的)
&& hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
上面這個過程是為了處理循環依賴的問題,在 Bean 實例化後就提前暴露這個對象,如果真的出現了循環依賴,如果這個 Bean 需要進行代理,那麼就不得不提前為它創建一個代理對象,雖然這個 Bean 還未初始化,不是一個「成熟態」。
關於 Spring 如何處理循環依賴的過程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 – 單例 Bean 的循環依賴處理》
postProcessBeforeInstantiation 方法
postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
,Bean 的創建過程中實例化前置處理,也就是允許你在創建 Bean 之前進行處理。如果該方法返回的不為 null
,後續 Bean 載入過程不會繼續,也就是說這個方法可用於獲取一個 Bean 對象。通常這裡用於創建 AOP 代理對象,或者 RPC 遠程調用的實現(因為本地類沒有遠程能力,可以通過這種方式進行攔截)。
該方法定義在 InstantiationAwareBeanPostProcessor 中,實現如下:
/**
* 在載入 Bean 的過程中,Bean 實例化的前置處理
* 如果返回的不是 null 則不會進行後續的載入過程,也就是說這個方法用於獲取一個 Bean 對象
* 通常這裡用於創建 AOP 代理對象,返回的對象不為 null,則會繼續調用下面的 {@link this#postProcessAfterInitialization} 方法進行初始化後置處理
* 參考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation}
*
* @param beanClass the class of the bean to be instantiated
* @param beanName the name of the bean
* @return 代理對象或者空對象
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// <1> 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
Object cacheKey = getCacheKey(beanClass, beanName);
// <2> 如果沒有 beanName 或者沒有自定義生成 TargetSource
if (!StringUtils.hasLength(beanName) // 沒有 beanName
|| !this.targetSourcedBeans.contains(beanName)) // 沒有自定義生成 TargetSource
{
/*
* <2.1> 已創建代理對象(或不需要創建),則直接返回 null,進行後續的 Bean 載入過程
*/
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/*
* <2.2>不需要創建代理對象,則直接返回 null,進行後續的 Bean 載入過程
*/
if (isInfrastructureClass(beanClass) // 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記介面)
|| shouldSkip(beanClass, beanName)) // 應該跳過
{
// 將這個 Bean 不需要創建代理對象的結果保存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
/*
* <3> 通過自定義 TargetSourceCreator 創建自定義 TargetSource 對象
* 默認沒有 TargetSourceCreator,所以這裡通常都是返回 null
*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
/*
* <4> 如果 TargetSource 不為空,表示需要創建代理對象
*/
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
// <4.1> 將當前 beanName 保存至集合,表示這個 Bean 已自定義生成 TargetSource 對象
this.targetSourcedBeans.add(beanName);
}
// <4.2> 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// <4.3> 創建代理對象,JDK 動態代理或者 CGLIB 動態代理
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// <4.4> 將代理對象的 Class 對象(目標類的子類)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <4.5> 返回代理對象
return proxy;
}
// <5> 否則,直接返回 null,進行後續的 Bean 載入過程
return null;
}
該方法的處理過程如下:
-
獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
-
如果沒有
beanName
或者沒有自定義生成 TargetSource- 已創建代理對象(或不需要創建),則直接返回
null
,進行後續的 Bean 載入過程 - 滿足下面其中一個條件表示不需要創建代理對象,則直接返回
null
,並將這個 Bean 不需要創建代理對象的結果保存至advisedBeans
中- 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記介面)
- 應該跳過
- 已創建代理對象(或不需要創建),則直接返回
-
通過自定義 TargetSourceCreator 創建自定義 TargetSource 對象,默認沒有 TargetSourceCreator,所以這裡通常都是返回
null
@Nullable protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { if (this.customTargetSourceCreators != null && this.beanFactory != null && this.beanFactory.containsBean(beanName)) { for (TargetSourceCreator tsc : this.customTargetSourceCreators) { // 通過 TargetSourceCreator 獲取 `beanName` 的自定義 TargetSource TargetSource ts = tsc.getTargetSource(beanClass, beanName); if (ts != null) { return ts; } } } return null; }
-
如果 TargetSource 不為空,表示需要創建代理對象
- 將當前
beanName
保存至targetSourcedBeans
集合,表示這個 Bean 已自定義生成 TargetSource 對象 - 調用
getAdvicesAndAdvisorsForBean(..)
方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序),在後面進行分析👨🎓 - 調用
createProxy(..)
方法,創建代理對象,JDK 動態代理或者 CGLIB 動態代理,在後面進行分析👨🎓 - 將代理對象的 Class 對象(目標類的子類)保存至
proxyTypes
- 返回代理對象
- 將當前
-
否則,直接返回
null
,進行後續的 Bean 載入過程
這裡先解釋一下 TargetSource,這個對象表示目標類的來源,用於獲取代理對象的目標對象,上面如果存在 TargetSourceCreator,表示可以創建自定義的 TargetSource,也就需要進行 AOP 代理。默認情況下是沒有 TargetSourceCreator 的,具體使用場景目前還沒有接觸過。
上面的 4.2
和 4.3
兩個方法非常複雜,放在後面進行分析😈
同樣對於 postProcessBeforeInstantiation(..)
方法在哪被調用,可能你已經忘記了,這裡來回顧一下:
// 在 AbstractAutowireCapableBeanFactory#createBean 創建 Bean 的過程中,開始前會執行下面步驟
/**
* <3> 在實例化前進行相關處理,會先調用所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
* 注意,如果這裡返回對象不是 `null` 的話,不會繼續往下執行原本初始化操作,直接返回,也就是說這個方法返回的是最終實例對象
* 可以通過這種方式提前返回一個代理對象,例如 AOP 的實現,或者 RPC 遠程調用的實現(因為本地類沒有遠程能力,可以通過這種方式進行攔截)
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 如果 RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的),並且存在 InstantiationAwareBeanPostProcessor 處理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 實例化前置處理
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 後置處理
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
上面過程是提供一種擴展點,可以讓你在 Bean 創建之前進行相關處理,例如進行 AOP 代理,或者 RPC 遠程調用的實現(因為本地類沒有遠程能力,可以通過這種方式進行攔截)。
關於 Spring Bean 的創建過程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 – Bean 的創建過程》
postProcessAfterInitialization 方法
postProcessAfterInitialization(@Nullable Object bean, String beanName)
,Bean 的初始化後置處理,在 Bean 初始化後,已經進入一個「成熟態」,那麼此時就可以創建 AOP 代理對象了,如果有必要的話。
該方法定義在 BeanPostProcessor 中,實現如下:
/**
* 在載入 Bean 的過程中,Bean 初始化的後置處理
* 參考 {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)}
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
// <1> 如果 bean 不為空則進行接下來的處理
if (bean != null) {
// <1.1> 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
Object cacheKey = getCacheKey(bean.getClass(), beanName);
/*
* <1.2> 移除 `earlyProxyReferences` 集合中保存的當前 Bean 對象(如果有的話)
* 如果 earlyProxyReferences 集合中沒有當前 Bean 對象,表示在前面沒有創建代理對象
*/
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 這裡嘗試為這個 Bean 創建一個代理對象(如果有必要的話)
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
// <2> 直接返回 bean 對象
return bean;
}
該方法的處理過程如下:
-
如果
bean
不為空則進行接下來的處理-
獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
-
移除
earlyProxyReferences
集合中保存的當前 Bean 對象(如果有的話),如果earlyProxyReferences
集合中沒有當前 Bean 對象,表示在前面沒有創建代理對象【重點】那麼調用
wrapIfNecessary(..)
方法,嘗試為這個 Bean 創建一個代理對象(如果有必要的話),該方法在後面分析👨🎓
-
-
直接返回
bean
對象
對於 postProcessAfterInitialization(..)
方法在哪被調用,可能你已經忘記了,這裡來回顧一下:
// 在 AbstractAutowireCapableBeanFactory#doCreateBean#initializeBean 創建 Bean 的過程中,屬性填充後會進行初始化,初始化後會執行下面的操作
/**
* <4> **初始化**階段的**後置處理**,執行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法
*
* 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中會添加 {@link ApplicationListenerDetector} 處理器
* 如果是單例 Bean 且為 ApplicationListener 類型,則添加到 Spring 應用上下文,和 Spring 事件相關
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 遍歷所有 BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 初始化的後置處理,返回 `current` 處理結果
Object current = processor.postProcessAfterInitialization(result, beanName);
// 處理結果為空,則直接返回 `result`
if (current == null) {
return result;
}
// 否則,`result` 複製 `current`
result = current;
}
return result;
}
上面這個過程在 Bean 初始化後,提供一個擴展點允許對這個 Bean 進行後置處理,此時 Bean 進入一個 「成熟態」,在這裡則可以進行 AOP 代理對象的創建
關於 Spring Bean 的初始化過程,如果你不熟悉可查看我的另一篇文章《死磕Spring之IoC篇 – Bean 的創建過程》
wrapIfNecessary 方法
wrapIfNecessary(Object bean, String beanName, Object cacheKey)
,該方法用於創建 AOP 代理對象,如果有必要的話
上面的 getEarlyBeanReference(..)
和 postProcessAfterInitialization(..)
方法都會調用這個方法,如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
/*
* <1> 如果當前 Bean 已經創建過自定義 TargetSource 對象
* 表示在上面的**實例化前置處理**中已經創建代理對象,那麼直接返回這個對象
*/
if (StringUtils.hasLength(beanName)
&& this.targetSourcedBeans.contains(beanName))
{
return bean;
}
// <2> `advisedBeans` 保存了這個 Bean 沒有必要創建代理對象,則直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* <3> 不需要創建代理對象,則直接返回當前 Bean
*/
if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記介面)
|| shouldSkip(bean.getClass(), beanName)) // 應該跳過
{
// 將這個 Bean 不需要創建代理對象的結果保存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// <4> 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <5> 如果有 Advisor,則進行下面的動態代理創建過程
if (specificInterceptors != DO_NOT_PROXY) {
// <5.1> 將這個 Bean 已創建代理對象的結果保存至 `advisedBeans`
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// <5.2> 創建代理對象,JDK 動態代理或者 CGLIB 動態代理
// 這裡傳入的是 SingletonTargetSource 對象,可獲取代理對象的目標對象(當前 Bean)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// <5.3> 將代理對象的 Class 對象(目標類的子類)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <5.4> 返回代理對象
return proxy;
}
// <6> 否則,將這個 Bean 不需要創建代理對象的結果保存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <7> 返回這個 Bean 對象
return bean;
}
該方法處理過程如下:
-
如果當前 Bean 已經創建過自定義 TargetSource 對象,表示在上面的實例化前置處理中已經創建代理對象,那麼直接返回這個對象
-
如果
advisedBeans
保存了這個 Bean 沒有必要創建代理對象,則直接返回這個對象 -
如果滿足下面其中一個條件,表示不需要創建代理對象,則直接返回當前 Bean,並將這個 Bean 不需要創建代理對象的結果保存至
advisedBeans
中- 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記接
- 應該跳過
-
調用
getAdvicesAndAdvisorsForBean(..)
方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序),在後面進行分析👨🎓 -
如果有 Advisor,則進行下面的動態代理創建過程
-
將這個 Bean 已創建代理對象的結果保存至
advisedBeans
-
調用
createProxy(..)
方法,創建代理對象,JDK 動態代理或者 CGLIB 動態代理,在後面進行分析👨🎓注意,這裡傳入的是 SingletonTargetSource 對象,可獲取代理對象的目標對象(當前 Bean)
-
將代理對象的 Class 對象(目標類的子類)保存至
proxyTypes
-
返回代理對象
-
-
否則,將這個 Bean 不需要創建代理對象的結果保存至
advisedBeans
-
返回這個 Bean 對象
到這裡,getEarlyBeanReference(..)
、postProcessBeforeInstantiation(..)
和 postProcessAfterInitialization(..)
三個方法的 AOP 自動代理過程主要分為兩步:
-
調用
getAdvicesAndAdvisorsForBean(..)
方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序) -
調用
createProxy(..)
方法,根據找到的 Advisor 創建一個代理對象,JDK 動態代理或者 CGLIB 動態代理
上面的流程看起來並不複雜,看著好像就調用兩個方法,不過不要被表象所迷惑,這只是冰山一角。
總結
Spring AOP 自動代理是通過實現 Spring IoC 中的幾種 BeanPostProcessor 處理器,在 Bean 的載入過程中進行擴展,如果有必要的話(找到了能夠應用於這個 Bean 的 Advisor)則創建 AOP 代理對象, JDK 動態代理或者 CGLIB 動態代理。
AbstractAutoProxyCreator 則是自動代理的入口,實現了三種 BeanPostProcessor 處理器,SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor 和 BeanPostProcessor,實現的三個方法:
-
getEarlyBeanReference(..)
:用於處理早期暴露的對象,如果有必要的話會創建一個代理對象 -
postProcessBeforeInstantiation(..)
:Bean 的創建過程中實例化前置處理,允許你在創建 Bean 之前進行處理。如果該方法返回的不為null
,後續 Bean 載入過程不會繼續,也就是說這個方法可用於獲取一個 Bean 對象。通常這裡用於創建 AOP 代理對象,或者 RPC 遠程調用的實現(因為本地類沒有遠程能力,可以通過這種方式進行攔截)。 -
postProcessAfterInitialization(..)
:Bean 的初始化後置處理,在 Bean 初始化後,已經進入一個「成熟態」,那麼此時就可以創建 AOP 代理對象了,如果有必要的話。
詳細過程參考上面的方法,我們主要是通過第 3
種方法創建代理對象,這三種方法的處理過程主要分為以下兩步:
-
調用
getAdvicesAndAdvisorsForBean(..)
方法,篩選出合適的 Advisor 對象們 -
調用
createProxy(..)
方法,根據找到的 Advisor 創建一個代理對象,JDK 動態代理或者 CGLIB 動態代理
由於這兩個步驟都比較複雜,考慮到文章的可讀性,所以另起兩篇文章分別分析