死磕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 進行處理,例如:

  1. 在 Bean 的實例化前,會調用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(..) 方法進行處理

  2. 在 Bean 出現循環依賴的情況下,會調用 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(..) 方法對提前暴露的 Bean 進行處理

  3. 在 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-aopaspectjweaver 兩個模組,然後通過下面的方式開啟 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 {}
}

只要存在 EnableAspectJAutoProxyAspectAdviceAnnotatedElement 四個 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);
}

該方法的處理過程如下:

  1. 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象
  2. 將當前 Bean 保存至 earlyProxyReferences 集合(早期的代理應用對象),也就是說當這個 Bean 出現循環依賴了,在實例化後就創建了代理對象(如果有必要),可以防止後續初始化後再次創建代理對象
  3. 【重點】調用 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;
}

該方法的處理過程如下:

  1. 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象

  2. 如果沒有 beanName 或者沒有自定義生成 TargetSource

    1. 已創建代理對象(或不需要創建),則直接返回 null,進行後續的 Bean 載入過程
    2. 滿足下面其中一個條件表示不需要創建代理對象,則直接返回 null,並將這個 Bean 不需要創建代理對象的結果保存至 advisedBeans
      • 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記介面)
      • 應該跳過
  3. 通過自定義 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;
    }
    
  4. 如果 TargetSource 不為空,表示需要創建代理對象

    1. 將當前 beanName 保存至 targetSourcedBeans 集合,表示這個 Bean 已自定義生成 TargetSource 對象
    2. 調用 getAdvicesAndAdvisorsForBean(..) 方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序),在後面進行分析👨‍🎓
    3. 調用 createProxy(..) 方法,創建代理對象,JDK 動態代理或者 CGLIB 動態代理,在後面進行分析👨‍🎓
    4. 將代理對象的 Class 對象(目標類的子類)保存至 proxyTypes
    5. 返回代理對象
  5. 否則,直接返回 null,進行後續的 Bean 載入過程

這裡先解釋一下 TargetSource,這個對象表示目標類的來源,用於獲取代理對象的目標對象,上面如果存在 TargetSourceCreator,表示可以創建自定義的 TargetSource,也就需要進行 AOP 代理。默認情況下是沒有 TargetSourceCreator 的,具體使用場景目前還沒有接觸過。

上面的 4.24.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;
}

該方法的處理過程如下:

  1. 如果 bean 不為空則進行接下來的處理

    1. 獲取這個 Bean 的快取 Key,默認為 Bean 的名稱,沒有則取其對應的 Class 對象

    2. 移除 earlyProxyReferences 集合中保存的當前 Bean 對象(如果有的話),如果 earlyProxyReferences 集合中沒有當前 Bean 對象,表示在前面沒有創建代理對象

      【重點】那麼調用 wrapIfNecessary(..) 方法,嘗試為這個 Bean 創建一個代理對象(如果有必要的話),該方法在後面分析👨‍🎓

  2. 直接返回 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;
}

該方法處理過程如下:

  1. 如果當前 Bean 已經創建過自定義 TargetSource 對象,表示在上面的實例化前置處理中已經創建代理對象,那麼直接返回這個對象

  2. 如果 advisedBeans 保存了這個 Bean 沒有必要創建代理對象,則直接返回這個對象

  3. 如果滿足下面其中一個條件,表示不需要創建代理對象,則直接返回當前 Bean,並將這個 Bean 不需要創建代理對象的結果保存至 advisedBeans

    • 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記接
    • 應該跳過
  4. 調用 getAdvicesAndAdvisorsForBean(..) 方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序),在後面進行分析👨‍🎓

  5. 如果有 Advisor,則進行下面的動態代理創建過程

    1. 將這個 Bean 已創建代理對象的結果保存至 advisedBeans

    2. 調用 createProxy(..) 方法,創建代理對象,JDK 動態代理或者 CGLIB 動態代理,在後面進行分析👨‍🎓

      注意,這裡傳入的是 SingletonTargetSource 對象,可獲取代理對象的目標對象(當前 Bean)

    3. 將代理對象的 Class 對象(目標類的子類)保存至 proxyTypes

    4. 返回代理對象

  6. 否則,將這個 Bean 不需要創建代理對象的結果保存至 advisedBeans

  7. 返回這個 Bean 對象

到這裡,getEarlyBeanReference(..)postProcessBeforeInstantiation(..)postProcessAfterInitialization(..) 三個方法的 AOP 自動代理過程主要分為兩步:

  1. 調用 getAdvicesAndAdvisorsForBean(..) 方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)

  2. 調用 createProxy(..) 方法,根據找到的 Advisor 創建一個代理對象,JDK 動態代理或者 CGLIB 動態代理

上面的流程看起來並不複雜,看著好像就調用兩個方法,不過不要被表象所迷惑,這只是冰山一角。

AOP

總結

Spring AOP 自動代理是通過實現 Spring IoC 中的幾種 BeanPostProcessor 處理器,在 Bean 的載入過程中進行擴展,如果有必要的話(找到了能夠應用於這個 Bean 的 Advisor)則創建 AOP 代理對象, JDK 動態代理或者 CGLIB 動態代理。

AbstractAutoProxyCreator 則是自動代理的入口,實現了三種 BeanPostProcessor 處理器,SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor 和 BeanPostProcessor,實現的三個方法:

  1. getEarlyBeanReference(..):用於處理早期暴露的對象,如果有必要的話會創建一個代理對象

  2. postProcessBeforeInstantiation(..):Bean 的創建過程中實例化前置處理,允許你在創建 Bean 之前進行處理。如果該方法返回的不為 null,後續 Bean 載入過程不會繼續,也就是說這個方法可用於獲取一個 Bean 對象。通常這裡用於創建 AOP 代理對象,或者 RPC 遠程調用的實現(因為本地類沒有遠程能力,可以通過這種方式進行攔截)。

  3. postProcessAfterInitialization(..):Bean 的初始化後置處理,在 Bean 初始化後,已經進入一個「成熟態」,那麼此時就可以創建 AOP 代理對象了,如果有必要的話。

詳細過程參考上面的方法,我們主要是通過第 3 種方法創建代理對象,這三種方法的處理過程主要分為以下兩步:

  1. 調用 getAdvicesAndAdvisorsForBean(..) 方法,篩選出合適的 Advisor 對象們

  2. 調用 createProxy(..) 方法,根據找到的 Advisor 創建一個代理對象,JDK 動態代理或者 CGLIB 動態代理

由於這兩個步驟都比較複雜,考慮到文章的可讀性,所以另起兩篇文章分別分析