死磕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 自動代理的入口是 AbstractAutoProxyCreator 對象,其中自動代理的過程主要分為下面兩步:

  1. 篩選出能夠應用於當前 Bean 的 Advisor
  2. 找到了合適 Advisor 則創建一個代理對象, JDK 動態代理或者 CGLIB 動態代理

上一篇《Spring AOP 自動代理(二)篩選合適的通知器》文章分析了上面第 1 步的處理過程,先去解析出當前 IoC 容器所有 Advisor 對象,包括 Advisor 類型的 Bean 和從 @AspectJ 註解的 Bean 解析出來的 Advisor 對象;然後通過通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器篩選出能夠應用於這個 Bean 的 Advisor 們,最後進行排序;不同的 AspectJ 根據 @Order 排序,同一個 AspectJ 中不同 Advisor 的排序,優先級:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

本文將會分析上面的第 2 的創建過程,如果這個 Bean 有合適的 Advisor,那麼為這個 Bean 創建一個代理對象,我們一起來看看是如何創建代理對象的。

回顧

// AbstractAutoProxyCreator.java
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;
}

在創建代理對象的過程中,上面方法的第 4 步嘗試獲取能夠應用於當前 Bean 的 Advisor,該過程在上一篇文章中進行分析過,如果有 Advisor,則調用 createProxy(..) 方法創建代理對象

注意,這裡傳入的 TargetSource 是一個 SingletonTargetSource 對象,可獲取目標對象,如下:

public class SingletonTargetSource implements TargetSource, Serializable {
	private static final long serialVersionUID = 9031246629662423738L;

	private final Object target;

	public SingletonTargetSource(Object target) {
		Assert.notNull(target, "Target object must not be null");
		this.target = target;
	}

	@Override
	public Class<?> getTargetClass() {
		return this.target.getClass();
	}

	@Override
	public Object getTarget() {
		return this.target;
	}

	@Override
	public void releaseTarget(Object target) {
		// nothing to do
	}

	@Override
	public boolean isStatic() {
		return true;
	}
}

創建代理對象的流程

  1. 創建一個 ProxyFactory 代理工廠對象,設置需要創建的代理類的配置信息,例如 Advisor 數組和 TargetSource 目標類來源

  2. 藉助 DefaultAopProxyFactory 選擇 JdkDynamicAopProxy(JDK 動態代理)還是 ObjenesisCglibAopProxy(CGLIB 動態代理)

    • proxy-target-classfalse 時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理

    • 如果為 true,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理

  3. 通過 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 創建一個代理對象

    • JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的 Proxy.newProxyInstance(..) 創建代理對象
    • ObjenesisCglibAopProxy 藉助 CGLIB 的 Enhancer 創建代理對象,會設置 Callback 數組和 CallbackFilter 篩選器(選擇合適 Callback 處理對應的方法),整個過程相比於 JDK 動態代理更複雜點,主要的實現在 DynamicAdvisedInterceptor 方法攔截器中

AbstractAutoProxyCreator

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator:AOP 自動代理的抽象類,完成主要的邏輯實現,提供一些骨架方法交由子類完成

1. createProxy 方法

createProxy(..) 方法,為目標對象創建一個代理對象,如下:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        // 為目標 Bean 的 BeanDefinition 對象設置一個屬性
        // org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass -> 目標 Bean 的 Class 對象
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // <1> 創建一個代理工廠
    ProxyFactory proxyFactory = new ProxyFactory();
    // <2> 複製當前 ProxyConfig 的一些屬性(例如 proxyTargetClass、exposeProxy)
    proxyFactory.copyFrom(this);

    /**
     * <3> 判斷是否類代理,也就是是否開啟 CGLIB 代理
     * 默認配置下為 `false`,參考 {@link org.springframework.context.annotation.EnableAspectJAutoProxy}
     */
    if (!proxyFactory.isProxyTargetClass()) {
        /*
         * <3.1> 如果這個 Bean 配置了進行類代理,則設置為 `proxyTargetClass` 為 `true`
         */
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            /*
             * <3.2> 檢測當前 Bean 實現的接口是否包含可代理的接口
             * 如沒有實現,則將 `proxyTargetClass` 設為 `true`,表示需要進行 CGLIB 提升
             */
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    /*
     * <4> 對入參的 Advisor 進一步處理,因為其中可能還存在 Advice 類型,需要將他們包裝成 DefaultPointcutAdvisor 對象
     * 如果配置了 `interceptorNames` 攔截器,也會添加進來
     */
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // <5> 代理工廠添加 Advisor 數組
    proxyFactory.addAdvisors(advisors);
    // <6> 代理工廠設置 TargetSource 對象
    proxyFactory.setTargetSource(targetSource);
    // <7> 對 ProxyFactory 進行加工處理,抽象方法,目前沒有子類實現
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // <8> 是否這個 AdvisedSupport 配置管理器已經過濾過目標類(默認為 false)
    if (advisorsPreFiltered()) {
        // 設置 `preFiltered` 為 `true`
        // 這樣 Advisor 們就不會根據 ClassFilter 進行過濾了,而直接通過 MethodMatcher 判斷是否處理被攔截方法
        proxyFactory.setPreFiltered(true);
    }

    // <9> 通過 ProxyFactory 代理工廠創建代理對象
    return proxyFactory.getProxy(getProxyClassLoader());
}

該方法的處理過程如下:

  1. 創建一個 ProxyFactory 代理工廠 proxyFactory
  2. 複製當前對象的一些屬性給 proxyFactory(例如 proxyTargetClass、exposeProxy),當前 AbstractAutoProxyCreator 對象繼承了 ProxyConfig
  3. 判斷是否類代理,也就是是否開啟 CGLIB 代理,默認配置下為 false,如果沒有的話,進行下面處理
    1. 如果這個 Bean 配置了進行類代理,則設置為 proxyTargetClasstrue
    2. 否則,檢測當前 Bean 實現的接口是否包含可代理的接口,如沒有實現,則將 proxyTargetClass 設為 true,表示需要進行 CGLIB 提升
  4. 調用 buildAdvisors(..) 方法,對入參的 Advisor 數組進一步處理,會將不是 Advisor 類型的對象包裝成 DefaultPointcutAdvisor 對象
  5. proxyFactory 代理工廠添加 Advisor 數組
  6. proxyFactory 代理工廠設置 TargetSource 對象,用戶獲取目標對象
  7. proxyFactory 進行加工處理,抽象方法,目前沒有子類實現
  8. 是否這個 AdvisedSupport 配置管理器已經過濾過目標類(默認為 false
    1. 是的話設置 preFilteredtrue,這樣 Advisor 們就不會根據 ClassFilter 進行過濾了,而直接通過 MethodMatcher 判斷是否處理被攔截方法
  9. 調用 proxyFactory 代理工廠的 getProxy(@Nullable ClassLoader classLoader) 方法創建代理對象

這個過程不複雜,容易理解,其中第 4 步會再次對 Advisor 數組進一步處理,在第 9 步根據 proxyFactory 創建代理對象

buildAdvisors 方法

buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) 方法,對 Advisor 數組進一步處理,如下:

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
    // Handle prototypes correctly...
    // <1> 將配置的 `interceptorNames` 轉換成 Advisor 類型(默認沒有)
    Advisor[] commonInterceptors = resolveInterceptorNames();

    // <2> 將 commonInterceptors 與 specificInterceptors 放入一個集合
    List<Object> allInterceptors = new ArrayList<>();
    if (specificInterceptors != null) {
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors.length > 0) {
            // 是否添加至最前面(默認為 true)
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    Advisor[] advisors = new Advisor[allInterceptors.size()];
    /*
     * <3> 遍歷 `specificInterceptors` 數組
     */
    for (int i = 0; i < allInterceptors.size(); i++) {
        // <3.1> 將不是 Advisor 類型的 Advice 或者 MethodInterceptor 包裝成 DefaultPointcutAdvisor 對象
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    // <4> 返回構建好的 Advisor 數組
    return advisors;
}

該方法的處理過程如下:

  1. 將配置的 interceptorNames 轉換成 Advisor 類型(默認沒有),得到 commonInterceptors 數組,如下:

    private Advisor[] resolveInterceptorNames() {
        BeanFactory bf = this.beanFactory;
        ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
        List<Advisor> advisors = new ArrayList<>();
        for (String beanName : this.interceptorNames) {
            if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
                Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
                Object next = bf.getBean(beanName);
                advisors.add(this.advisorAdapterRegistry.wrap(next));
            }
        }
        return advisors.toArray(new Advisor[0]);
    }
    

    解析 interceptorNames 中對應的 Bean,並包裝成 Advisor 類型(如果需要的話)

  2. 將上一步獲取到的 commonInterceptors 數組放入入參中的 specificInterceptors 數組中

  3. 遍歷 specificInterceptors 數組

    1. 將不是 Advisor 類型的 Advice 或者 MethodInterceptor 包裝成 DefaultPointcutAdvisor 對象

      // DefaultAdvisorAdapterRegistry.java
      @Override
      public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
          if (adviceObject instanceof Advisor) { // Advisor 類型,直接返回
              return (Advisor) adviceObject;
          }
          if (!(adviceObject instanceof Advice)) { // 非 Advice 接口,拋出異常
              throw new UnknownAdviceTypeException(adviceObject);
          }
          Advice advice = (Advice) adviceObject;
          if (advice instanceof MethodInterceptor) { // MethodInterceptor 類型,包裝成 DefaultPointcutAdvisor 對象
              // So well-known it doesn't even need an adapter.
              return new DefaultPointcutAdvisor(advice);
          }
          for (AdvisorAdapter adapter : this.adapters) {
              // Check that it is supported.
              // 檢查該 Advice 類型是否支持
              if (adapter.supportsAdvice(advice)) {
                  // 包裝成 DefaultPointcutAdvisor 對象 返回
                  return new DefaultPointcutAdvisor(advice);
              }
          }
          throw new UnknownAdviceTypeException(advice);
      }
      
  4. 返回構建好的 Advisor 數組

能夠應用於這個 Bean 的 Advisor 們已經準備好了,那麼接下來我們來看看 ProxyFactory 是如何創建代理對象的

2. ProxyFactory

org.springframework.aop.framework.ProxyFactory,代理工廠,如下:

public Object getProxy(@Nullable ClassLoader classLoader) {
    // <1> 先創建一個 AOP 代理類(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
    // <2> 根據 AOP 代理為目標 Bean 創建一個代理對象,並返回
    return createAopProxy().getProxy(classLoader);
}

過程分為兩步:

  1. 調用 createAopProxy() 方法,創建一個 AOP 代理類(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy),如下:

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        // <1> 先獲取 AOP 代理工廠,默認為 DefaultAopProxyFactory,只有這個實現
        // <2> 然後通過它根據創建當前 AdvisedSupport 配置管理器創建一個 AOP 代理(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
        return getAopProxyFactory().createAopProxy(this);
    }
    
  2. 然後調用 AOP 代理類的 getProxy(@Nullable ClassLoader classLoader) 方法獲取代理對象

可以看到選擇 JDK 動態代理還是選擇 CGLIB 動態代理在 DefaultAopProxyFactory 中可以找到答案

3. DefaultAopProxyFactory

org.springframework.aop.framework.DefaultAopProxyFactory,默認的 AOP 代理工廠,如下:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		/*
		 * <1> 判斷是否滿足下面三個條件的其中一個
		 */
		if (config.isOptimize() // 需要優化,默認為 `false`
				|| config.isProxyTargetClass() // 使用類代理,也就是使用 CGLIB 動態代理
				|| hasNoUserSuppliedProxyInterfaces(config) // 目標類沒有實現接口
		) {
			// <1.1> 獲取目標類
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			/*
			 * <1.2> 如果目標類是一個接口或者是 java.lang.reflect.Proxy 的子類
			 * 則還是使用 JDK 動態代理,創建一個 JdkDynamicAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
			 */
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// <1.3> 使用 CGLIB 動態代理,創建一個  ObjenesisCglibAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
			return new ObjenesisCglibAopProxy(config);
		}
		// <2> 否則
		else {
			// 使用 JDK 動態代理,創建一個 JdkDynamicAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
			return new JdkDynamicAopProxy(config);
		}
	}

	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

}

創建 AOP 代理類的過程如下:

  1. 判斷是否滿足下面三個條件的其中一個,則進行下面的處理

    需要優化,默認為 false

    使用類代理,也就是使用 CGLIB 動態代理,在前面的 AbstractAutoProxyCreator#createProxy(..) 方法中有提到過;

    目標類沒有實現接口;

    1. 獲取目標類
    2. 如果目標類是一個接口或者是 java.lang.reflect.Proxy 的子類,則還是使用JDK 動態代理,創建一個 JdkDynamicAopProxy 對象
    3. 否則,使用 CGLIB 動態代理,創建一個 ObjenesisCglibAopProxy 對象
  2. 否則,使用JDK 動態代理,創建一個 JdkDynamicAopProxy 對象

我們可以看到JDK 動態代理對應 JdkDynamicAopProxy 對象,CGLIB 動態代理對應 ObjenesisCglibAopProxy(繼承 CglibAopProxy)對象,在創建這兩個對象的時候都傳入了一個參數,就是 AdvisedSupport 配置管理器對象。

回到前面的 ProxyFactory#createAopProxy() 方法中,這個 AdvisedSupport 對象就是這個 ProxyFactory 對象,它繼承了 AdvisedSupport

再回到 AbstractAutoProxyCreator#createProxy(..) 方法中,這個 ProxyFactory 對象是在這創建的,包含了 TargetSource 目標類來源和能夠應用於當前目標對象的所有 Advisor

所以,我們得到的JdkDynamicAopProxy或者ObjenesisCglibAopProxy都包含了創建 AOP 代理對象的所有配置信息,可以創建代理對象了。

通過上面的這個方法,我們還可以得出一個結論,關於 proxy-target-class 配置的含義是什麼?

首先這個配置表示是否進行類代理,也就是 CGLIB 動態代理,默認是 false

當為 false 時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理

如果為 true,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理

到這裡,我們知道了使用哪種方式創建代理對象,那麼接下里我們一起來看看兩種方式創建代理對象的過程。

4. JdkDynamicAopProxy

org.springframework.aop.framework.JdkDynamicAopProxy,JDK 動態代理類,實現了 InvocationHandler 接口,可創建代理對象

構造函數

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = 5531744639992436476L;

	/** We use a static Log to avoid serialization issues. */
	private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

	/** 代理對象的配置信息,例如保存了 TargetSource 目標類來源、能夠應用於目標類的所有 Advisor */
	private final AdvisedSupport advised;

	/** 目標對象是否重寫了 equals 方法 */
	private boolean equalsDefined;

	/** 目標對象是否重寫了 hashCode 方法 */
	private boolean hashCodeDefined;

	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 // 沒有 Advisor,表示沒有任何動作
				&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 沒有來源
		{
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}
}

4.1 getProxy 方法

getProxy() 方法,獲取一個 JDK 動態代理對象,如下:

@Override
public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); }

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    // <1> 獲取需要代理的接口(目標類實現的接口,會加上 Spring 內部的幾個接口,例如 SpringProxy)
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    // <2> 判斷目標類是否重寫了 `equals` 或者 `hashCode` 方法
    // 沒有重寫在攔截到這兩個方法的時候,會調用當前類的實現
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // <3> 調用 JDK 的 Proxy#newProxyInstance(..) 方法創建代理對象
    // 傳入的參數就是當前 ClassLoader 類加載器、需要代理的接口、InvocationHandler 實現類
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

獲取代理對象的過程如下:

  1. 獲取需要代理的接口(目標類實現的接口,會加上 Spring 內部的幾個接口,例如 SpringProxy)

  2. 判斷目標類是否重寫了 equals 或者 hashCode 方法,沒有重寫在攔截到這兩個方法的時候,會調用當前類的實現

    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        for (Class<?> proxiedInterface : proxiedInterfaces) {
            Method[] methods = proxiedInterface.getDeclaredMethods();
            for (Method method : methods) {
                if (AopUtils.isEqualsMethod(method)) {
                    this.equalsDefined = true;
                }
                if (AopUtils.isHashCodeMethod(method)) {
                    this.hashCodeDefined = true;
                }
                if (this.equalsDefined && this.hashCodeDefined) {
                    return;
                }
            }
        }
    }
    
  3. 調用 JDK 的 Proxy#newProxyInstance(..) 方法創建代理對象,入參的 InvocationHandler 實現了就是當前對象

對於上面 JDK 創建代理對象的過程是不是很熟悉,不清楚的小夥伴可以查看我前面 《初識 JDK、CGLIB 兩種動態代理》 這篇文章

AopProxyUtils

org.springframework.aop.framework.AopProxyUtils 工具類,獲取 JDK 創建代理對象時需要實現哪些接口,如下:

static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    // <1> 獲取需要代理的接口(目標類實現的接口),放入 `specifiedInterfaces` 中
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
    if (specifiedInterfaces.length == 0) {
        // No user-specified interfaces: check whether target class is an interface.
        Class<?> targetClass = advised.getTargetClass();
        if (targetClass != null) {
            if (targetClass.isInterface()) {
                advised.setInterfaces(targetClass);
            }
            else if (Proxy.isProxyClass(targetClass)) {
                advised.setInterfaces(targetClass.getInterfaces());
            }
            specifiedInterfaces = advised.getProxiedInterfaces();
        }
    }
    // <2> 判斷目標類實現的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一個
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
        nonUserIfcCount++;
    }
    if (addAdvised) {
        nonUserIfcCount++;
    }
    if (addDecoratingProxy) {
        nonUserIfcCount++;
    }
    Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    int index = specifiedInterfaces.length;
    // <3> 如果目標類實現的接口沒有 SpringProxy,則添加一個
    // 這樣創建的代理對象就會實現這個接口,就能知道這個代理對象是否由 Spring 創建
    if (addSpringProxy) {
        proxiedInterfaces[index] = SpringProxy.class;
        index++;
    }
    // 添加一個 Advised 接口
    if (addAdvised) {
        proxiedInterfaces[index] = Advised.class;
        index++;
    }
    // 添加一個 DecoratingProxy 接口
    if (addDecoratingProxy) {
        proxiedInterfaces[index] = DecoratingProxy.class;
    }
    // <4> 返回需要代理的接口
    return proxiedInterfaces;
}

該方法的處理過程如下:

  1. 獲取需要代理的接口(目標類實現的接口),放入 specifiedInterfaces
  2. 判斷目標類實現的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一個
  3. 通常情況下,上面三個接口都會添加到 specifiedInterfaces 的後面
  4. 返回 specifiedInterfaces 數組

通過上面這個方法得到的結論:在 Spring 內部通過 JDK 創建的代理對象會實現額外的接口,包括 SpringProxy 標記接口,可區分代理對象是否為 Spring 創建的

4 CglibAopProxy

org.springframework.aop.framework.CglibAopProxy,CGLIB 動態代理類,可創建代理對象

CGLIB 動態代理比 JDK 動態代理可要複雜得多~

構造函數

class CglibAopProxy implements AopProxy, Serializable {

	// Constants for CGLIB callback array indices
	// 因為 CGLIB 設置的 Callback 是一個數組,下面定義了數組中固定幾個攔截器的位置
	// 進行 AOP 代理的通用攔截器
	private static final int AOP_PROXY = 0;
	// 執行目標方法的攔截器
	private static final int INVOKE_TARGET = 1;
	// 空的 Callback 對象,對於 finalize() 方法,不需要進行任何處理
	private static final int NO_OVERRIDE = 2;
	// 目標對象調度器,用於獲取目標對象
	private static final int DISPATCH_TARGET = 3;
	// 配置管理器的調度器,會返回一個 AdvisedSupport 對象
	private static final int DISPATCH_ADVISED = 4;
	// 處理 `equals(Object)` 方法的攔截器
	private static final int INVOKE_EQUALS = 5;
	// 處理 `hashCode()` 方法的攔截器
	private static final int INVOKE_HASHCODE = 6;

	/** Logger available to subclasses; static to optimize serialization. */
	protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);

	/** Keeps track of the Classes that we have validated for final methods. */
	private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<>();

	/** 代理對象的配置信息,例如保存了 TargetSource 目標類來源、能夠應用於目標類的所有 Advisor */
	protected final AdvisedSupport advised;

	/** 創建代理對象的構造方法入參 */
	@Nullable
	protected Object[] constructorArgs;

	/** 創建代理對象的構造方法的入參類型 */
	@Nullable
	protected Class<?>[] constructorArgTypes;

	/** Dispatcher used for methods on Advised. 配置管理器的調度器,會返回一個 AdvisedSupport 對象 */
	private final transient AdvisedDispatcher advisedDispatcher;

	/**
	 * 緩存方法的調用器數組索引
	 * key:方法名稱
	 * value:方法對應的方法調用器在 Callback 數組中的位置
	 */
	private transient Map<String, Integer> fixedInterceptorMap = Collections.emptyMap();

	// 方法調用器在 Callback 數組中的偏移量
	private transient int fixedInterceptorOffset;

	public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 // 沒有 Advisor,表示沒有任何動作
				&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 沒有來源
		{
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
		this.advisedDispatcher = new AdvisedDispatcher(this.advised);
	}
}

上面的每一個屬性都有注釋,都非常重要,在 Spring 的 CGLIB 動態代理創建代理對象時,會設置一個 Callback 數組,上面定義了數組中固定幾個攔截器的位置

數組中前面的幾個 Callback 如下:

  • 0:進行 AOP 代理的通用攔截器【重點關注】
  • 1:執行目標方法的攔截器
  • 2:空的 Callback 對象,例如 finalize() 方法,不需要進行任何處理
  • 3:目標對象調度器,用於獲取目標對象
  • 4:配置管理器的調度器,會返回一個 AdvisedSupport 對象
  • 5:處理 equals(Object) 方法的攔截器
  • 6:處理 hashCode() 方法的攔截器

4.1 getProxy 方法

getProxy() 方法,獲取一個 CGLIB 動態代理對象,如下:

@Override
public Object getProxy() { return getProxy(null); }

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    try {
        // <1> 獲取目標類
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        // <2> 將目標類作為被代理的類
        Class<?> proxySuperClass = rootClass;
        // <3> 如果目標類已經被 CGLIB 提升(名稱包含 `$$` 符號)
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            // <3.1> 獲取目標類的父類作為被代理的類
            proxySuperClass = rootClass.getSuperclass();
            // <3.2> 獲取目標類實現的接口,並添加至當前 AdvisedSupport 配置管理器中
            // 例如 `@Configuration` 註解的 Bean 會被 CGLIB 提升,實現了 EnhancedConfiguration 接口
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        // <4> 進行校驗,僅打印日誌,例如 final 修飾的方法不能被 CGLIB 提升
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        // <5> 創建 CGLIB 的增強類,並進行接下來的配置
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            // `useCache` 默認為 `true`,可通過 `cglib.useCache` 系統參數指定
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        // <5.1> 設置被代理的類
        enhancer.setSuperclass(proxySuperClass);
        // <5.2> 設置需要代理的接口(可能沒有,不過都會加上 Spring 內部的幾個接口,例如 SpringProxy)
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        // <5.3> 設置命名策略,默認生成的代理對象的名稱中包含 '$$' 和 'BySpringCGLIB'
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        // <5.4> 獲取回調接口,也就是 MethodInterceptor 方法攔截器
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        // <5.5> 設置 Callback 過濾器,用於篩選出方法對應的 Callback 回調接口
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        // <6> 創建代理對象,CGLIG 位元組碼替身,創建目標類的子類
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
        // 拋出 AopConfigException 異常
    }
    catch (Throwable ex) {
        // 拋出 AopConfigException 異常
    }
}

該方法的處理過程如下:

  1. 獲取目標類 rootClass
  2. 將目標類作為被代理的類 proxySuperClass
  3. 如果目標類已經被 CGLIB 提升(名稱包含 $$ 符號)
    1. 獲取目標類的父類作為被代理的類
    2. 獲取目標類實現的接口,並添加至當前 AdvisedSupport 配置管理器中,例如 @Configuration 註解的 Bean 會被 CGLIB 提升,實現了 EnhancedConfiguration 接口
  4. 進行校驗,僅打印日誌,例如 final 修飾的方法不能被 CGLIB 提升
  5. 創建 CGLIB 的增強類 Enhancer 對象,並進行接下來的配置
    1. 設置被代理的類為 proxySuperClass
    2. 設置需要代理的接口(例如 SpringProxy),在前面講述 JDK 動態代理創建代理對象時已經講過 AopProxyUtils 這個工具類,不同的是 CGLIB 不會添加 DecoratingProxy 這個接口
    3. 設置命名策略,默認生成的代理對象的名稱中包含 $$BySpringCGLIB
    4. 調用 getCallbacks(Class<?>) 方法,獲取回調數組 Callback[] callbacks,也就是 MethodInterceptor 方法攔截器
    5. 設置 Callback 過濾器為 ProxyCallbackFilter,用於篩選出方法使用 callbacks 中的哪個 Callback
  6. 調用 createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) 方法,創建代理對象,並返回

CGLIB 創建代理對象的過程整體上並不複雜,其中第 5.45.56 步我們接下來逐步分析

4.2 getCallbacks 方法

getCallbacks(Class<?> rootClass) 方法,獲取代理對象的 Callback 回調數組,如下:

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // Parameters used for optimization choices...
    // <1> 獲取代理對象的三個配置信息
    // `exposeProxy` 是否暴露代理對象,通常為 `false`
    boolean exposeProxy = this.advised.isExposeProxy();
    // `isFrozen` 配置管理器是否被凍結,通常為 `false`
    boolean isFrozen = this.advised.isFrozen();
    // `isStatic` 是否是靜態的目標對象,也就是說目標對象是否每次都需要創建,通常為 `true`
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // Choose an "aop" interceptor (used for AOP calls).
    // <2> 【重點】創建目標對象的攔截器,MethodInterceptor 方法攔截器,會對目標對象的方法進行攔截處理,之前篩選出來的 Advisor 會在這個裏面被調用
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    // Choose a "straight to target" interceptor. (used for calls that are
    // unadvised but can return this). May be required to expose the proxy.
    // <3> 創建目標對象的執行器,用於執行目標方法
    Callback targetInterceptor;
    // <3.1> 如果需要暴露當前代理對象,則通過 AopContext 進行暴露,放入 ThreadLocal 中,其他的和下面都相同
    if (exposeProxy) {
        targetInterceptor = (isStatic ?
                new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
    }
    // <3.2> 否則,不暴露
    else {
        targetInterceptor = (isStatic ?
                // <3.2.1> 用於執行方法代理對象,並對最終的返回結果進一步處理(返回結果是否需要為代理對象,返回結果是否不能為空)
                new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                // <3.2.2> 和上者的區別就是,每次攔截都會重新獲取目標對象,結束後釋放該目標對象
                new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
    }

    // Choose a "direct to target" dispatcher (used for
    // unadvised calls to static targets that cannot return this).
    // <4> 目標對象調度器,用於獲取目標對象
    Callback targetDispatcher = (isStatic ?
            // <4.1> 目標對象的調度器,用於獲取當前目標對象
            new StaticDispatcher(this.advised.getTargetSource().getTarget()) :
            // <4.2> 目標對象的調度器,空的 Callback,不做任何處理
            new SerializableNoOp());

    // <5> 生成主要的幾個回調接口,也就是上面創建的幾個 Callback,放入 `mainCallbacks` 數組
    Callback[] mainCallbacks = new Callback[] {
            // 0:進行 AOP 代理的通用攔截器
            aopInterceptor,  // for normal advice
            // 1:執行目標方法的攔截器
            targetInterceptor,  // invoke target without considering advice, if optimized
            // 2:空的 Callback 對象,例如 `finalize()` 方法,不需要進行任何處理
            new SerializableNoOp(),  // no override for methods mapped to this
            // 3:目標對象調度器,用於獲取目標對象
            targetDispatcher,
            // 4:配置管理器的調度器,會返回一個 AdvisedSupport 對象
            // 因為代理對象會實現 Advised 接口,攔截到其裏面的方法時,需要調用當前 AdvisedSupport 的方法
            this.advisedDispatcher,
            // 5:處理 `equals(Object)` 方法的攔截器
            new EqualsInterceptor(this.advised),
            // 6:處理 `hashCode()` 方法的攔截器
            new HashCodeInterceptor(this.advised)
    };

    Callback[] callbacks;

    // If the target is a static one and the advice chain is frozen,
    // then we can make some optimizations by sending the AOP calls
    // direct to the target using the fixed chain for that method.
    /*
     * <6> 如果目標對象不需要每次都創建,且當前 AdvisedSupport 配置管理器被凍結了,性能優化,可暫時忽略
     * 那麼在創建代理對象的時候,就可以先將目標對象的每個方法對應的方法調用器解析出來,該過程有點性能損耗,這樣在代理對象執行方法的時候性能有所提升
     * 不過由於這裡會解析出許多方法調用器,會佔有一定的內存,以空間換時間
     */
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<>(methods.length);

        // TODO: small memory optimization here (can skip creation for methods with no advice)
        /*
         * <6.1> 遍歷目標對象所有的方法
         */
        for (int x = 0; x < methods.length; x++) {
            Method method = methods[x];
            // <6.1.1> 獲取能夠應用於該方法的所有攔截器(有序)
            // 不同的 AspectJ 根據 @Order 排序
            // 同一個 AspectJ 中的 Advice 排序:AspectJAfterThrowingAdvice > AfterReturningAdviceInterceptor > AspectJAfterAdvice > AspectJAroundAdvice > MethodBeforeAdviceInterceptor
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
            // <6.1.2> 創建一個方法調用器
            fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                    chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
            // <6.1.3> 將每個方法的對應的調用器的位置索引緩存起來
            this.fixedInterceptorMap.put(methods.toString(), x);
        }

        // Now copy both the callbacks from mainCallbacks
        // and fixedCallbacks into the callbacks array.
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        // <6.2> 將 `mainCallbacks` 複製到 `callbacks` 數組
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        // <6.3> 將 `fixedCallbacks` 複製到 `callbacks` 數組(拼接在後面)
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
        // <6.4> 記錄一個已生成的方法調用器的偏移量
        this.fixedInterceptorOffset = mainCallbacks.length;
    }
    // <7> 否則,不進行解析,取上面的幾個主要的 Callback
    else {
        callbacks = mainCallbacks;
    }
    // <8> 返回這個目標對象對應的 Callback 數組
    return callbacks;
}

該方法的處理過程如下:

  1. 是獲取代理對象的三個配置信息

    • exposeProxy 是否暴露代理對象,通常為 false
    • isFrozen 配置管理器是否被凍結,通常為 false
    • isStatic 是否是靜態的目標對象,也就是說目標對象是否每次都需要創建,通常為 true
  2. 【重點】創建目標對象的攔截器,DynamicAdvisedInterceptor 方法攔截器,會對目標對象的方法進行攔截處理,代理對象的處理邏輯都在這裏面完成

  3. 創建目標對象的執行器,用於執行目標方法

    1. 如果需要暴露當前代理對象,則通過 AopContext 進行暴露,放入 ThreadLocal 中,其他的和下面都相同
    2. 否則,不暴露
      1. isStatic 為 true,創建 StaticUnadvisedInterceptor 對象,用於執行方法代理對象,並對最終的返回結果進一步處理(返回結果是否需要為代理對象,返回結果是否不能為空)
      2. 否則,創建 DynamicUnadvisedInterceptor 對象,和上者的區別就是,每次攔截都會重新獲取目標對象,結束後釋放該目標對象
  4. 目標對象調度器,用於獲取目標對象

    1. isStatic 為 true,創建 StaticDispatcher 對象,目標對象的調度器,用於獲取當前目標對象
    2. 否則,創建 SerializableNoOp 對象,空的 Callback,不做任何處理
  5. 生成主要的幾個回調接口,也就是上面創建的幾個 Callback,放入 mainCallbacks 數組,可以回到上面的構造函數看看哦😈

    0:進行 AOP 代理的通用攔截器

    1:執行目標方法的攔截器

    2:空的 Callback 對象,例如 finalize() 方法,不需要進行任何處理

    3:目標對象調度器,用於獲取目標對象

    4:配置管理器的調度器,會返回一個 AdvisedSupport 對象,因為代理對象會實現 Advised 接口,攔截到其裏面的方法時,需要調用當前 AdvisedSupport 的方法

    5:處理 equals(Object) 方法的攔截器

    6:處理 hashCode() 方法的攔截器

  6. 如果目標對象不需要每次都創建,且當前 AdvisedSupport 配置管理器被凍結了(默認不會),這一步做了一個性能優化,具體查看上面的代碼

    在創建代理對象的時候,就可以先將目標對象的每個方法對應的方法調用器解析出來,該過程有點性能損耗,這樣在代理對象執行方法的時候性能有所提升;不過由於這裡會解析出許多方法調用器,會佔有一定的內存,以空間換時間

  7. 否則,不進行解析,取上面 mainCallbacks

  8. 返回這個目標對象對應的 Callback 數組

獲取代理對象的 Callback 過程稍微有點複雜,因為代理對象處理不同的方法使用到的 Callback 也是不同的。不過你要知道的是上面第 2 步,第一個 Callback 就是 DynamicAdvisedInterceptor 對象,該對象用於進行 AOP 代理的通用攔截器,目標類的方法在這個攔截器中進行處理。這個對象和 JDK 動態代理創建的代理對象的實現差不多,所以都放入下一篇文章進行分析😈

4.3 ProxyCallbackFilter

CglibAopProxy 的私有內部靜態類,用於篩選方法出對應的 Callback 對象

private static class ProxyCallbackFilter implements CallbackFilter {

    private final AdvisedSupport advised;

    private final Map<String, Integer> fixedInterceptorMap;

    private final int fixedInterceptorOffset;

    public ProxyCallbackFilter(
            AdvisedSupport advised, Map<String, Integer> fixedInterceptorMap, int fixedInterceptorOffset) {
        this.advised = advised;
        this.fixedInterceptorMap = fixedInterceptorMap;
        this.fixedInterceptorOffset = fixedInterceptorOffset;
    }

    /**
     * 根據 Method 返回我們需要的 Callback 在數組中的位置
     */
    @Override
    public int accept(Method method) {
        // <1> 如果該方法是 `finalize()`
        if (AopUtils.isFinalizeMethod(method)) {
            // 返回一個空 Callback 對象,不對該方法做任何處理
            return NO_OVERRIDE;
        }
        // <2> 如果該方法是 Advised 中的方法,也就是需要 AdvisedSupport 來執行
        if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // 返回一個配置管理器的調度器,會返回一個 AdvisedSupport 對象去執行這個方法
            return DISPATCH_ADVISED;
        }
        // We must always proxy equals, to direct calls to this.
        // <3> 如果該方法是 `equals(Object)` 方法
        if (AopUtils.isEqualsMethod(method)) {
            // 返回處理 `equals(Object)` 方法的攔截器去執行該方法
            return INVOKE_EQUALS;
        }
        // We must always calculate hashCode based on the proxy.
        // <4> 如果該方法是 `hashCode()` 方法
        if (AopUtils.isHashCodeMethod(method)) {
            // 返回處理 `hashCode()` 方法的攔截器去執行該方法
            return INVOKE_HASHCODE;
        }
        // <5> 獲取目標類 Class 對象
        Class<?> targetClass = this.advised.getTargetClass();
        // Proxy is not yet available, but that shouldn't matter.
        // <6> 獲取能夠應用於該方法的所有攔截器,僅判斷是否存在 Advice
        List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        boolean haveAdvice = !chain.isEmpty();
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isStatic = this.advised.getTargetSource().isStatic();
        boolean isFrozen = this.advised.isFrozen();
        // <7> 如果有 Advice 或者配置沒有被凍結,通常情況都會進入這裡
        if (haveAdvice || !isFrozen) {
            // If exposing the proxy, then AOP_PROXY must be used.
            // <7.1> 如果需要暴露這個代理對象,默認為 `false`
            if (exposeProxy) {
                // 返回處理 AOP 代理的通用攔截器去執行該方法
                return AOP_PROXY;
            }
            String key = method.toString();
            // Check to see if we have fixed interceptor to serve this method.
            // Else use the AOP_PROXY.
            // <7.2> 如果目標對象是單例的,且配置被凍結,且存在對應的方法調用器
            if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
                // We know that we are optimizing so we can use the FixedStaticChainInterceptors.
                // 返回已經存在的方法調用器
                int index = this.fixedInterceptorMap.get(key);
                return (index + this.fixedInterceptorOffset);
            }
            // <7.3> 否則(通常會走到這一步)
            else {
                // 返回處理 AOP 代理的通用攔截器去執行該方法
                return AOP_PROXY;
            }
        }
        // <8> 否則
        else {
            // <8.1> 如果需要暴露代理對象,或者不是單例模式,默認這兩種情況都不滿足
            if (exposeProxy || !isStatic) {
                // 則返回執行目標方法的攔截器
                return INVOKE_TARGET;
            }
            Class<?> returnType = method.getReturnType();
            // <8.2> 如果該方法需要返回的就是目標類,暫時不清楚這種情況
            if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
                // 那麼返回執行目標方法的攔截器,返回當前對象
                return INVOKE_TARGET;
            }
            // <8.3> 否則,返回目標對象調度器,用於獲取目標對象,讓目標對象自己去執行這個方法
            else {
                return DISPATCH_TARGET;
            }
        }
    }
}

我們直接看到實現的 accept(Method method) 方法的處理邏輯:

  1. 如果該方法是 finalize(),返回一個空 Callback 對象,不對該方法做任何處理
  2. 如果該方法是 Advised 中的方法,也就是需要 AdvisedSupport 來執行,返回一個配置管理器的調度器,會返回一個 AdvisedSupport 對象去執行這個方法
  3. 如果該方法是 equals(Object) 方法,返回處理 equals(Object) 方法的攔截器去執行該方法
  4. 如果該方法是 hashCode() 方法,返回處理 hashCode() 方法的攔截器去執行該方法
  5. 獲取目標類 Class 對象
  6. 獲取能夠應用於該方法的所有攔截器,僅判斷是否存在 Advice
  7. 如果有 Advice 或者配置沒有被凍結,通常情況都會進入這裡
    1. 如果需要暴露這個代理對象,默認為 false,返回處理 AOP 代理的通用攔截器去執行該方法
    2. 如果目標對象是單例的,且配置被凍結,且存在對應的方法調用器,返回已經存在的方法調用器
    3. 否則(通常會走到這一步),返回進行 AOP 代理的通用攔截器去執行該方法
  8. 否則
    1. 如果需要暴露代理對象,或者不是單例模式,默認這兩種情況都不滿足,返回執行目標方法的攔截器
    2. 如果該方法需要返回的就是目標類,暫時不清楚這種情況,那麼返回執行目標方法的攔截器,返回當前對象
    3. 否則,返回目標對象調度器,用於獲取目標對象,讓目標對象自己去執行這個方法

上面的處理過程基本上都根據 Method 進行判斷,然後返回一個 int 數值,這個值代表去取 Callback 數組中的那個 Callback,回看上面講到的幾個方法你就全部理解了。

我們來看到上面的第 7.3 步,返回的是一個 0,表示使用第一個 Callback 進行處理,對應的就是 DynamicAdvisedInterceptor 對象,這個對象和 JDK 動態代理創建的代理對象的實現差不多,所以都放入下一篇文章進行分析😈

4.4 createProxyClassAndInstance 方法

createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) 方法,創建代理對象,如下:

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    // 設置使用構造器期間不進行攔截
    enhancer.setInterceptDuringConstruction(false);
    // 設置 Callback 數組
    enhancer.setCallbacks(callbacks);
    // 創建一個代理對象(目標類的子類)
    return (this.constructorArgs != null && this.constructorArgTypes != null ?
            // 使用指定的構造方法
            enhancer.create(this.constructorArgTypes, this.constructorArgs) :
            // 使用默認的構造方法
            enhancer.create());
}

這個方法在 ObjenesisCglibAopProxy 子類中被重寫了,Spring 內部也是使用 ObjenesisCglibAopProxy 這個類,因為 CGLIB 創建的子類考慮到通過構造器實例化代理對象,可能會存在構造器不合適的情況,所以 Spring 採用 Objenesis 實例化對象,不通過構造器創建實例對象

4.4 ObjenesisCglibAopProxy

org.springframework.aop.framework.ObjenesisCglibAopProxy,繼承 CglibAopProxy 類,重寫 createProxyClassAndInstance(..) 方法

class ObjenesisCglibAopProxy extends CglibAopProxy {

	/**
	 * 創建一個 Objenesis 對象
	 * [**Objenesis**](//objenesis.org/) 是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象
	 * 應用場景:
	 * 1. 序列化,遠程調用和持久化 - 對象需要實例化並存儲為到一個特殊的狀態,而沒有調用代碼
	 * 2. 代理,AOP 庫和 Mock 對象 - 類可以被子類繼承而子類不用擔心父類的構造器
	 * 3. 容器框架 - 對象可以以非標準的方式被動態實例化
	 */
	private static final SpringObjenesis objenesis = new SpringObjenesis();

	public ObjenesisCglibAopProxy(AdvisedSupport config) {
		super(config);
	}

	@Override
	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		// <1> 先創建代理對象的 Class 對象(目標類的子類)
		Class<?> proxyClass = enhancer.createClass();
		Object proxyInstance = null;

		// <2> 是否使用 Objenesis 來實例化代理對象,默認會
		// 可通過 在 `spring.properties` 文件中添加 `spring.objenesis.ignore=false` 來禁止
		if (objenesis.isWorthTrying()) {
			try {
				// <2.1> 通過 Objenesis 實例化代理對象(非標準方式,不使用構造方法進行實例化)
				proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
			}
			catch (Throwable ex) {
				logger.debug("Unable to instantiate proxy using Objenesis, " +
						"falling back to regular proxy construction", ex);
			}
		}

		// <3> 如果藉助 Objenesis 實例化代理對象失敗
		if (proxyInstance == null) {
			// Regular instantiation via default constructor...
			try {
				// <3.1> 選擇構造器,指定了參數則使用對應的構造器,否則使用默認構造器
				Constructor<?> ctor = (this.constructorArgs != null ?
						proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
						proxyClass.getDeclaredConstructor());
				ReflectionUtils.makeAccessible(ctor);
				// <3.2> 通過構造器實例化代理對象(反射)
				proxyInstance = (this.constructorArgs != null ?
						ctor.newInstance(this.constructorArgs) : ctor.newInstance());
			}
			catch (Throwable ex) {
				throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
						"and regular proxy instantiation via default constructor fails as well", ex);
			}
		}

		// <4> 設置 Callback 數組
		((Factory) proxyInstance).setCallbacks(callbacks);
		// <5> 返回代理對象
		return proxyInstance;
	}
}

首先我們來看到 SpringObjenesis 這個對象,它實現了 Objenesis 接口,Objenesis 是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象,應用場景:

  • 序列化,遠程調用和持久化 – 對象需要實例化並存儲為到一個特殊的狀態,而沒有調用代碼
  • 代理,AOP 庫和 Mock 對象 – 類可以被子類繼承而子類不用擔心父類的構造器
  • 容器框架 – 對象可以以非標準的方式被動態實例化

創建代理對象的過程如下:

  1. 先通過 Enhancer 創建代理對象的 Class 對象(目標類的子類)
  2. 是否使用 Objenesis 來實例化代理對象,默認會
    1. 通過 Objenesis 實例化代理對象(非標準方式,不使用構造方法進行實例化)
  3. 如果藉助 Objenesis 實例化代理對象失敗
    1. 選擇構造器,指定了參數則使用對應的構造器,否則使用默認構造器
    2. 通過構造器實例化代理對象(反射)
  4. 設置 Callback 數組
  5. 返回代理對象

總結

在前面的《Spring AOP 自動代理(一)入口》文章中,分析了 Spring AOP 自動代理的入口是 AbstractAutoProxyCreator 對象,其中自動代理的過程主要分為下面兩步:

  1. 篩選出能夠應用於當前 Bean 的 Advisor
  2. 找到了合適 Advisor 則創建一個代理對象, JDK 動態代理或者 CGLIB 動態代理

上一篇《Spring AOP 自動代理(二)篩選合適的通知器》文章分析了上面第 1 步的處理過程。本文是接着前面兩篇文章分析上面第 2 個過程,Spring 是如何創建代理對象的,大致流程如下:

  1. 創建一個 ProxyFactory 代理工廠對象,設置需要創建的代理類的配置信息,例如 Advisor 數組和 TargetSource 目標類來源

  2. 藉助 DefaultAopProxyFactory 選擇 JdkDynamicAopProxy(JDK 動態代理)還是 ObjenesisCglibAopProxy(CGLIB 動態代理)

    • proxy-target-classfalse 時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理

    • 如果為 true,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理

  3. 通過 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 創建一個代理對象

    • JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的 Proxy.newProxyInstance(..) 創建代理對象
    • ObjenesisCglibAopProxy 藉助 CGLIB 的 Enhancer 創建代理對象,會設置 Callback 數組和 CallbackFilter 篩選器(選擇合適 Callback 處理對應的方法),整個過程相比於 JDK 動態代理更複雜點,主要的實現在 DynamicAdvisedInterceptor 方法攔截器中

其中 CGLIB 實例化代理對象的過程使用到了 Objenesis,它是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象。因為 CGLIB 創建的子類考慮到通過構造器實例化代理對象,可能會存在構造器不合適的情況,所以 Spring 採用 Objenesis 實例化對象,不通過構造器創建實例對象。

好了,本篇文章就到這裡了,Spring AOP 中整個自動代理過程到這裡也就結束了。對於 JDK 動態代理和 CGLIB 動態代理創建的代理對象,它們的具體實現(或者說是方法攔截處理)在這裡並沒有體現出來,前者的實現在 JdkDynamicAopProxy 中,因為它實現了 InvocationHandler 接口,後者的實現則在 DynamicAdvisedInterceptor 方法攔截器中,這些內容將在下篇文章進行分析。