深入理解 SpringAOP(二):AOP的執行流程

概述

在之前的文章中,我們已經對 SpringAOP 的關鍵組件進行了描述,並且瞭解了其基本操作和流程。在本文中,我們將進一步深入源碼,揭示 SpringAOP 的內部實現細節,理解其運行機制的每個環節,包括切面的織入方式、代理對象的創建過程、連接點的定位與匹配等。通過對完整運行流程的深入研究,我們能夠更全面地理解 SpringAOP 的工作原理,並且能夠更好地利用和擴展這一功能。

本專題共三篇文章,這是第二篇:

  • 深入理解 SpringAOP(一):AOP 組件概述
  • 深入理解 SpringAOP(二):AOP的執行流程;
  • 深入理解 SpringAOP(三):AspectJ支持;

一、代理生效時機

在前文,我們提到了代理基於 AbstractAutoProxyCreator 的子類生效,因此直接觀察該類,我們可以注意到 AbstractAutoProxyCreator 中實現了 SmartInstantiationAwareBeanPostProcessor ,說明他可能在三個關鍵節點觸發代理:

  • InstantiationAwareBeanPostProcessor :在實例化階段,即 bean 實例化前後;
  • SmartInstantiationAwareBeanPostProcessor:早期引用創建階段,即在循環依賴中,當 bean 已實例化而未被初始化時,被其他依賴它的 bean 通過 getEarlyBeanReference 方法從一級緩存中獲取;
  • BeanPostProcessor:在初始化階段,即 bean 完成初始化後,進行依賴注入與各種聲明週期回調前後;

1、在實例化階段

InstantiationAwareBeanPostProcessor 分別提供了 postProcessBeforeInstantiationpostProcessAfterInstantiation 兩個方法用於介入 bean 的實例化流程,其中 AbstractAutoProxyCreator 實現了前者:

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
	Object cacheKey = getCacheKey(beanClass, beanName);

	// 如果其未指定自定義的目標源
	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
		// 如果已經被代理
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
		// 是基礎設施類,或者需要跳過
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}

	// 如果用戶指定的自定義的目標源,則嘗試獲取目標源並根據其創建代理
	// Create proxy here if we have a custom TargetSource.
	// Suppresses unnecessary default instantiation of the target bean:
	// The TargetSource will handle target instances in a custom fashion.
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		if (StringUtils.hasLength(beanName)) {
			this.targetSourcedBeans.add(beanName);
		}
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
		Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	return null;
}

protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
	// 如果有 beanName,則使用 beanName 作爲 key
	if (StringUtils.hasLength(beanName)) {
		return (FactoryBean.class.isAssignableFrom(beanClass) ?
				BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
	}
	// 否則使用類型作爲 key
	else {
		return beanClass;
	}
}

這段代碼的作用是在實例化Bean之前進行處理。它檢查Bean是否需要被代理:

  • 如果需要,根據自定義目標源創建代理對象,並返回代理對象;
  • 如果不需要代理或者不存在自定義目標源,則直接返回 null,即走正常的 bean 實例化邏輯;

它主要是用來在更靈活的創建代理目標的,一般我們並不會用到,因此這裏瞭解即可。

2、作爲早期引用被創建時

SmartInstantiationAwareBeanPostProcessor 提供了三個方法,AbstractAutoProxyCreator 實現了兩個:

  • predictBeanType :確認 bean 的類型,這裏會直接獲取代理對象的類型;
  • getEarlyBeanReference :獲取對象早期引用,這裏會通過 wrapIfNecessary 嘗試爲 bean 創建代理對象;

在開始前,我們需要明確,什麼是早期引用
一般情況下,Spring 會在 bean 初始化完畢後纔會基於該 bean 實例創建代理對象,但是在循環引用時,比如 beanA 依賴 beanB 依賴 beanA 的情況下,由於後創建的 beanB 需要依賴先創建的 beanA,而在此時先創建的 beanA 並未完成初始化,則此時後創建的 beanB 會通過一級緩存中的 ObjectFactory ,也就是 () → getEarlyBeanReference 方法提前獲得基於 beanB 創建的代理對象(如果不需要代理則就是 beanA 本身),這就是早期引用。
不過,雖然是早期引用階段,但是實際上在這裏創建代理對象的邏輯是與正常的初始化後創建代理對象的邏輯基本一致的:

public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	this.earlyProxyReferences.put(cacheKey, bean);
	return wrapIfNecessary(bean, beanName, cacheKey);
}

後文我們需要重點關注 wrapIfNecessary 方法,不過目前我們知道在這一步會創建代理對象即可。

3、在初始化階段

SmartInstantiationAwareBeanPostProcessor 提供了兩個方法,AbstractAutoProxyCreator 只實現了其中的 postProcessBeforeInstantiation ,在初始化前,它將爲 bean 生成代理對象:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 如果在早期階段已經創建過了,就不必再創建一次了
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

getEarlyBeanReference 基本一致,都是基於 wrapIfNecessary 完成的,只不過是時機不同。正常需要代理的 bean 會在這裏被替換爲代理對象。

二、創建代理對象前的準備

知道了代理對象在何時被創建,也大概瞭解了相關的基本組件,現在我們需要真正的瞭解代理對象是如何被創建的,通知、切點和通知器這些組件將會在這個過程中扮演怎樣的角色。
wrapIfNecessary 方法則是入口,在這個方法中,spring 會確認 bean 是否需要被代理,如果是就爲其創建代理對象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// 指定的目標源的對象不需要再代理(因爲在初始化階段就處理完了)
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	// 已經被代理則不需要再代理
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	// 如果是基礎設施類,或者需要跳過就不代理
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// 爲 bean 獲取需要的通知器
	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		// 註明該 bean 已經被代理
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// 爲其創建代理
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}

1、爲 bean 獲取通知器

當獲得一個 bean 時,spring 會通過 getAdvicesAndAdvisorsForBean 方法爲這個 bean 獲得它需要的通知器與通知,在 AbstractAutoProxyCreator 它是個空實現,AbstractAdvisorAutoProxyCreator 實現了

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

	// 查找符合條件的通知器
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 獲取 spring 容器中所有的 Advisor
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

// 獲取 spring 容器中所有的 Advisor
// 就是字面意思,從 BeanFactory 中實例化所有 Advisor 並返回
protected List<Advisor> findCandidateAdvisors() {
	Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
	return this.advisorRetrievalHelper.findAdvisorBeans();
}

protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

	// 一個類似 TransactionSynchronizationManager 的上下文,用於記錄當前正在創建代理對象的 bean 的一些信息
	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}
	finally {
		// 將其從上下文中移除
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

整體邏輯比較直觀,總共就三步:

  • BeanFactory 加載並獲取所有的 Advisor
  • 從這些 Advisor 中篩選出 bean 需要的部分;
  • 將這些 Advisor@Order 或者 Ordered 接口排序;

值得一提的是,在 AnnotationAwareAspectJAutoProxyCreator 中,它對 findCandidateAdvisors 進行了重寫,在原有邏輯的基礎上添加了基於 AspectJ 生成的 Advisor ,這裏暫且先知道即可。

2、篩選匹配通知器

這裏我們額外的看一下 AopUtils.findAdvisorsThatCanApply 方法,它揭露了通知器 Advisor 是如何判斷是否需要爲這個 bean 應用切點的:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new ArrayList<>();
	for (Advisor candidate : candidateAdvisors) {
		// 如果是針對類型匹配
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

public static boolean canApply(Advisor advisor, Class<?> targetClass) {
	return canApply(advisor, targetClass, false);
}

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	// 如果針對類型攔截
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
	// 如果針對方法攔截
	else if (advisor instanceof PointcutAdvisor pca) {
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}

	// 獲取方法匹配器
	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}

	// 如果可以同時針對方法和類型匹配
	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	for (Class<?> clazz : classes) {
		// 獲取這個 bean 中直接聲明的方法
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		for (Method method : methods) {
			// 根據方法、或者同時根據方法與類型判斷是否要應用通知
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}

這裏大體處理了兩類匹配邏輯:

  • 如果通知器是 IntroductionAdvisor  類型,則通過通知器的 ClassFilter 進行類型匹配;
  • 如果通知器是 PointcutAdvisor  類型,則通過通知器的 Pointcut 切點中的 ClassFilterMethodMatcher 分別對類型和類中的方法進行匹配。不過,針對 MethodMatcher 又分兩種情況:
    1. MethodMatcherIntroductionAwareMethodMatcher  類型,說明支持同時根據方法和 bean 的類型進行匹配;
    2. 如果不是,則說明只支持根據方法進行匹配;

3、確認代理類型

讓我們回到 wrapIfNecessary ,現在我們得到了所有可以作用於 bean 上的 Advisor ,接下來就需要根據這些 Advisor 去創建代理對象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// ... ...

		// 獲取可作用於 bean 的 Advisor
		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 創建代理對象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

createProxy 是其中的關鍵方法,不過主要的內容在於要基於接口還是類進行代理:

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

	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
	}

	// 根據 ProxyConfig(就是 AbstractAutoProxyCreator 本身)創建代理工廠
	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);

	// 如果需要基於目標類而不是其接口代理(即這個代理類沒實現接口)
	// 並且他們已經被 jdk 代理了(比如 Annotation 或者 Mybatis 的 Mapper),或者是根據 lambda 生成的匿名內部類
	// 那麼生成的代理類需要實現這些接口類型
	if (proxyFactory.isProxyTargetClass()) {
		// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
			// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
			for (Class<?> ifc : beanClass.getInterfaces()) {
				proxyFactory.addInterface(ifc);
			}
		}
	}
	// 其他情況下,根據 beanDefinition 中的 preserveTargetClass 屬性
	// 判斷是否要直接基於這個類而不是其接口創建代理對象,簡而言之,就是要不要走 CGLib 代理
	else {
		// No proxyTargetClass flag enforced, let's apply our default checks...
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		// 否則直接從這個類實現的接口中尋找可以用於代理的接口
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	// 創建 Advisor 
	// 一般情況下,這裏就是各種 Advisor,不過也可能混有用於支持 AspectJ 的特殊對象,因此需要在這裏統一處理
	// 轉爲 Advisor 
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	// 是否要啓用 advisor 的預過濾,在 AbstractAutoProxyCreator 中總是返回 false
	// 因此我們可以認爲總是爲 true
	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// 獲取類加載器,然後創建代理對象
	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
		classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
	}
	return proxyFactory.getProxy(classLoader);
}

protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
	Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
	boolean hasReasonableProxyInterface = false;
	for (Class<?> ifc : targetInterfaces) {
		// 確認接口是否滿足下列條件,如果是那就使用它作爲代理接口:
		// 1、是否不爲 Aware 這樣的 Spring 回調接口
		// 2、是否不爲 cglib.proxy.Factory 這樣的內部接口
		// 3、是否有定義抽象方法(如果沒有抽象方法那自然也沒必要代理了)
		if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
				ifc.getMethods().length > 0) {
			hasReasonableProxyInterface = true;
			break;
		}
	}
	// 如果找到了代理接口,說明需要基於接口代理
	// 那就讓代理對象實現所有的接口
	if (hasReasonableProxyInterface) {
		// Must allow for introductions; can't just set interfaces to the target's interfaces only.
		for (Class<?> ifc : targetInterfaces) {
			proxyFactory.addInterface(ifc);
		}
	}
	// 如果沒有找到代理接口,那就讓他基於對象本身的類型生成代理
	else {
		proxyFactory.setProxyTargetClass(true);
	}
}

暫且忽略代理工廠 ProxyFactory 中的邏輯,這裏主要做了這麼個判斷:

  1. 如果 proxyFactory 設置了 proxyTargetClass 標誌爲 true,則說明要使用目標類(target class)作爲代理的基礎。在這種情況下,如果目標類是JDK動態代理的代理類或者是 Lambda 表達式生成的匿名內部類,則需要特殊處理,即通過遍歷目標類的接口,將這些接口添加到代理工廠中,以保證代理對象具備這些接口的方法;
  2. 如果 proxyFactoryproxyTargetClass 標誌沒有設置爲 true,則執行下面的邏輯。這表示沒有顯式要求使用目標類作爲代理基礎,並且可以根據一些默認規則進行判斷:
    a. 如果根據默認規則確定應該使用目標類作爲代理基礎,則將 proxyTargetClass 標誌設置爲 true ,即需要進行 CGLib 代理;
    b. 如果不滿足使用目標類作爲代理基礎的條件,則根據目標類的接口情況來設置代理工廠的接口。通過調用 evaluateProxyInterfaces(beanClass, proxyFactory) 方法,根據目標類的接口信息,將適合的接口添加到代理工廠中;

4、適配通知器

另外,在 createProxy 中,會調用 buildAdvisors 去適配通知器,這是雖然一般情況下輸入的 specificInterceptors 大部分都是 Advisor ,不過也可能有一些其他的類型需要特殊處理,比如大家都很熟悉的 MethodInterceptor,它只實現了 Advice 接口,因此需要在這裏被適配爲 DefaultPointcutAdvisor
總而言之,在創建代理對象前,需要調用適配器將裏面入參的 Object 類型的數組 specificInterceptors ,全部確保轉爲 Advisor

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
	// 有些攔截器是直接通過把 beanName 設置到 AbstractAutoProxyCreator 註冊的
	// 因此此處需要將他們直接取出來
	// Handle prototypes correctly...
	Advisor[] commonInterceptors = resolveInterceptorNames();

	// 收集所有可用的攔截器
	List<Object> allInterceptors = new ArrayList<>();
	if (specificInterceptors != null) {
		if (specificInterceptors.length > 0) {
			// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
		}
		if (commonInterceptors.length > 0) {
			if (this.applyCommonInterceptorsFirst) {
				allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
			}
			else {
				allInterceptors.addAll(Arrays.asList(commonInterceptors));
			}
		}
	}
	if (logger.isTraceEnabled()) {
		int nrOfCommonInterceptors = commonInterceptors.length;
		int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
		logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
				" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
	}
	
	// 調用通知器適配器註冊表 advisorAdapterRegistry,嘗試將所有的攔截器對象適配爲通知器
	Advisor[] advisors = new Advisor[allInterceptors.size()];
	for (int i = 0; i < allInterceptors.size(); i++) {
		advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
	}
	return advisors;
}

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]);
}

這裏我們需要看一下 AdvisorAdapterRegistry 的唯一一個實現類 DefaultAdvisorAdapterRegistrywrap 方法:

@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
	// 已經是 Advisor 了,直接返回
	if (adviceObject instanceof Advisor) {
		return (Advisor) adviceObject;
	}
	// 沒有實現 Advice 接口,直接拋異常
	if (!(adviceObject instanceof Advice advice)) {
		throw new UnknownAdviceTypeException(adviceObject);
	}
	// 是方法攔截器,這是最常見的實現
	if (advice instanceof MethodInterceptor) {
		// So well-known it doesn't even need an adapter.
		return new DefaultPointcutAdvisor(advice);
	}
	// 不是上述兩者,則調用 AdvisorAdapter 鏈嘗試將其適配爲 Advisor 
	for (AdvisorAdapter adapter : this.adapters) {
		// Check that it is supported.
		if (adapter.supportsAdvice(advice)) {
			return new DefaultPointcutAdvisor(advice);
		}
	}
	throw new UnknownAdviceTypeException(advice);
}

這裏的邏輯還是比較直白的:

  • 如果已經是 Advisor 了,就直接返回;
  • 如果不是 Advisor ,那必須是 Advice ,否則直接拋異常;
  • 如果它是 MethodInterceptor ,那就將其適配爲 DefaultPointcutAdvisor (可能是考慮到 spring 中幾乎九成九的 AOP 都是基於 MethodInterceptor 實現的,因此這裏直接專門提出來了);
  • 如果是其他情況,就調用適配器鏈,找到一個支持處理這個攔截器的 AdvisorAdapter 去對它做適配;

三、創建代理對象

經歷了一番波折,現在我們得到了所有最終可用的 Advisor ,以及在 ProxyFactory 設置好了代理類要實現哪些類型,現在我們看看 ProxyFactory.getProxy 是如何創建代理對象的:

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		// 獲取 AOP 代理工廠,默認爲 DefaultAopProxyFactory
		return getAopProxyFactory()
			.createAopProxy(this);
	}

1、確認代理方式

在默認情況下,getAopProxyFactory 會獲得一個 DefaultAopProxyFactory 實例,在 createAopProxy 方法中,會根據各種條件決定要使用何種方式生成代理:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	private static final long serialVersionUID = 7930414337282325166L;

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			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.");
			}
			// 如果在上文獲取到的代理類型,若滿足下述任意條件,則使用 JDK 代理:
			// 1、代理的目標類是接口;
			// 2、代理的目標類本身就是個代理類
			// 3、代理的目標類是基於 Lambda 表達式生成的匿名內部類
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}

			// 否則基於 Cglib 代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

	/**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

}

這裏主要做了這三層判斷:

  1. 如果應用程序運行在 Native Image環境中(即原生鏡像化環境,例如 GraalVM 的 Native Image 模式),則直接返回使用JDK動態代理 JdkDynamicAopProxy
  2. 如果配置中設置了優化標誌 optimize,或者配置中設置了 proxyTargetClass 標誌,或者沒有提供用戶自定義的代理接口(即沒有明確指定要代理的接口),則需要進一步判斷:
    a. 如果目標類 targetClass 爲空,則拋出 AopConfigException 異常,提示無法確定目標類;
    b. 如果目標類是接口類型 targetClass.isInterface(),或者是JDK動態代理的代理類 Proxy.isProxyClass(targetClass),或者是Lambda表達式生成的類 ClassUtils.isLambdaClass(targetClass),則返回使用JDK動態代理;
    c. 如果以上條件都不滿足,即目標類既不是接口也不是代理類,那麼返回使用CGLIB動態代理 ObjenesisCglibAopProxy
  3. 如果以上條件都不滿足,則默認使用JDK動態代理 JdkDynamicAopProxy

簡而言之,僅當代理的目標類沒有接口,且不是代理類的時候,纔會使用 Cglib 基於子類生成代理對象,這也是爲什麼即使我們的 bean 沒有實現任何接口,Spring 依然能夠生成代理的原因。

2、創建代理類

現在,通過 ProxyFactory 中的 AopProxyFactory ,我們可能獲得 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 對象,我們以比較常見的 JdkDynamicAopProxy 爲例,看看它是如何真正的創建代理對象的:

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
	}

這裏平平無奇的直接調用了 Proxy.newProxyInstance ,那麼顯然一切的奧祕都在最後作爲 InvocationHandler 傳入的這個 this ,也就是 JdkDynamicAopProxy 本身。
先看看它的成員變量和構造函數:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	// 代理對象的生成配置,即 AbstractAutoProxyCreator 本身
	// 此處保存有該 bean 的 Advisor 與代理方法的映射關係,以及該代理對象實現的接口類型
	// 本身也是一個 Advised,當我通過代理對象調用 Advised 接口中聲明的方法時,都會轉發到這裏
	private final AdvisedSupport advised;
	
	// 代理對象要實現哪些接口
	private final Class<?>[] proxiedInterfaces;

	// 是否有重寫 hashCode 或者 equals 方法
	private boolean equalsDefined;
	private boolean hashCodeDefined;

	/**
	 * Construct a new JdkDynamicAopProxy for the given AOP configuration.
	 * @param config the AOP configuration as AdvisedSupport object
	 * @throws AopConfigException if the config is invalid. We try to throw an informative
	 * exception in this case, rather than let a mysterious failure happen later.
	 */
	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
		// 確認是否有重新 hashCode 或者 equals 放方法
		this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
	}
}

在創建代理前,它會先添加一些默認的接口:

static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
	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) || ClassUtils.isLambdaClass(targetClass)) {
				advised.setInterfaces(targetClass.getInterfaces());
			}
			specifiedInterfaces = advised.getProxiedInterfaces();
		}
	}

	// 添加 SpringProxy、Advised 接口
	List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
	for (Class<?> ifc : specifiedInterfaces) {
		// Only non-sealed interfaces are actually eligible for JDK proxying (on JDK 17)
		if (!ifc.isSealed()) {
			proxiedInterfaces.add(ifc);
		}
	}
	if (!advised.isInterfaceProxied(SpringProxy.class)) {
		proxiedInterfaces.add(SpringProxy.class);
	}
	if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
		proxiedInterfaces.add(Advised.class);
	}
	// 如果通知器 DecoratingProxy,就讓代理對象也實現 DecoratingProxy
	if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
		proxiedInterfaces.add(DecoratingProxy.class);
	}
	return ClassUtils.toClassArray(proxiedInterfaces);
}

3、代理方法

InvocationHandler.invoke 是代理對象攔截待執行方法的關鍵,在 JdkDynamicAopProxy 中,它區分了五類方法,並做了不同的處理,這裏我們主要關注後續通過 getInterceptorsAndDynamicInterceptionAdvice 獲取通知調用鏈的部分:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;

	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
		// 調用 eqlues 方法
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			return equals(args[0]);
		}
		// 調用 hashCode 方法
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			return hashCode();
		}
		// 如果調用的方法來自於 DecoratingProxy 接口
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		// 如果這個方法來自於 Advised 接口,那就調用 Advised
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		// 真正的調用的進行增強,即調用 AOP 植入的各種前置和後置放阿飛
		Object retVal;

		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// 獲取目標的對象
		// Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 獲取攔截器鏈
		// Get the interception chain for this method.
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// 如果
		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		if (chain.isEmpty()) {
			// We can skip creating a MethodInvocation: just invoke the target directly
			// Note that the final invoker must be an InvokerInterceptor so we know it does
			// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// We need to create a method invocation...
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			retVal = invocation.proceed();
		}

		// 
		// Massage return value if necessary.
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

4、獲取攔截器鏈

通過  AdvisedSupport (其實就是 ProxyFactory)的 getInterceptorsAndDynamicInterceptionAdvice 方法,可以獲得由所有的實際要執行方法的攔截器鏈:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		// 拿到攔截器鏈後緩存一下,下次調用就不用再找了
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

其中,AdvisorChainFactory 默認只有 DefaultAdvisorChainFactory 一個實現類,因此我們直接看它的 getInterceptorsAndDynamicInterceptionAdvice 方法即可:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// 獲取所有的通知器
	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
	Advisor[] advisors = config.getAdvisors();
	List<Object> interceptorList = new ArrayList<>(advisors.length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	Boolean hasIntroductions = null;
	
	// 按順序遍歷通知器
	for (Advisor advisor : advisors) {

		// 1、如果基於方法切點攔截,則根據方法切點判斷通知是否生效
		if (advisor instanceof PointcutAdvisor pointcutAdvisor) {

			// 由於 isPreFiltered 必定爲 true,因此這裏實際上就是看看方法切點是否支持處理這個類型的 bean
			// Add it conditionally.
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {

				// 支持處理這個類型,那就根據方法或者方法與類型判斷是否要執行該切點
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				boolean match;
				if (mm instanceof IntroductionAwareMethodMatcher) {
					if (hasIntroductions == null) {
						hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
					}
					match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
				}
				else {
					match = mm.matches(method, actualClass);
				}

				// 通知生效
				if (match) {
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					// 如果這個方法檢查器是動態的,即每次調用的時候才檢查是否生效,那就將其包裝爲 InterceptorAndDynamicMethodMatcher
					if (mm.isRuntime()) {
						// Creating a new object instance in the getInterceptors() method
						// isn't a problem as we normally cache created chains.
						for (MethodInterceptor interceptor : interceptors) {
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
			}
		}

		// /2、如果基於類攔截,則基於類確認該通知是否生效
		else if (advisor instanceof IntroductionAdvisor ia) {
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		// 3、其他的情況,比如基於 AspectJ,直接將其包裝爲 MethodInterceptor
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

可以看到,這裏主要是檢查將各種不同類型的 Advisor 是否支持處理該類型的 bean,如果是,就將其轉爲 MethodInterceptor ,然後收集所有的攔截器湊成鏈後,返回給代理對象:

  • 如果當前的 Advisor 是一個 PointcutAdvisor,即基於切點的通知器,那麼:
    1. 先根據切點的 ClassFilter 判斷是否匹配成功,然後再根據節點的 MethodMatcher 的類型,覺得要根據方法還是同時根據方法與類進行匹配;
    2. 如果匹配成功,再判斷 MethodMatcher 是否根據方法調用情況動態的決定是否匹配,若是則將其包裝爲 InterceptorAndDynamicMethodMatcher 並添加到攔截器鏈;
  • 如果當前的 Advisor 是一個IntroductionAdvisor,即引介增強器,那麼根據類過濾器的匹配規則判斷是否需要將它添加到攔截器鏈中;
  • 如果當前的 Advisor 不是上述兩種類型,直接將它的攔截器數組添加到攔截器鏈中;

5、執行攔截器鏈

回到 invoke 方法,現在我們通過 getInterceptorsAndDynamicInterceptionAdvice 方法獲取調用鏈後,就該真正的執行它的:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		// ... ...

		// 真正的調用的進行增強,即調用 AOP 植入的各種前置和後置放阿飛
		Object retVal;

		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// 獲取目標的對象
		// Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 獲取攔截器鏈
		// Get the interception chain for this method.
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// 如果
		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		if (chain.isEmpty()) {
			// We can skip creating a MethodInvocation: just invoke the target directly
			// Note that the final invoker must be an InvokerInterceptor so we know it does
			// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// 獲取攔截器鏈
			// We need to create a method invocation...
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			retVal = invocation.proceed();
		}

		// ... ...
}

執行上下文

其中,ReflectiveMethodInvocation 是一個包含了本次調用信息的一個執行上下文,它將在攔截器鏈中流轉以完成全部的流程:

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {

	// 代理對象
	protected final Object proxy;

	// 原始對象與代理的方法
	@Nullable
	protected final Object target;
	protected final Method method;

	// 本次調用的參數
	protected Object[] arguments;
	// 調用對象的類型
	@Nullable
	private final Class<?> targetClass;

	// 一些特殊的參數
	@Nullable
	private Map<String, Object> userAttributes;

	// 攔截器鏈
	protected final List<?> interceptorsAndDynamicMethodMatchers;

	// 當前調用的攔截器鏈的下標
	private int currentInterceptorIndex = -1;

	protected ReflectiveMethodInvocation(
			Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
			@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

		this.proxy = proxy;
		this.target = target;
		this.targetClass = targetClass;
		this.method = BridgeMethodResolver.findBridgedMethod(method); // 如果代理的是橋接方法,那就找到它的原始方法
		this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments); // 這裏會根據方法入參類型適配一下入參
		this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; // 攔截器鏈
	}
}

調用攔截器鏈

當我們調用 ReflectiveMethodInvocation.proceed 方法的時候,實際上是會先調用攔截器鏈:

public Object proceed() throws Throwable {
	// 如果沒有攔截器,直接調用方法本身
	// We start with an index of -1 and increment early.
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	
	// 獲取攔截器,並讓 currentInterceptorIndex + 1
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

	// 如果是動態攔截器,就根據當前的調用參數判斷是否要應用它
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		// 如果不需要,就跳過跳過該攔截器
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			return proceed();
		}
	}
	// 如果就是靜態的方法攔截器,那就直接調用攔截器
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

protected Object invokeJoinpoint() throws Throwable {
	return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

這個地方稍微有點繞,大概意思是這樣的:

  • 首先,ReflectiveMethodInvocation 在內部維護了一個成員變量 currentInterceptorIndex ,代表了當前調用到第幾個攔截器;
  • 每當調用了一個攔截器後,都會使 currentInterceptorIndex 加一,也就是說,每當調用一次 proceed 方法,都相當於執行了一個攔截器;
  • currentInterceptorIndex 等於攔截器鏈的長度減一時,意味着所有的攔截器都調用完畢,此時真正的調用被攔截的方法;

在這個基礎上,每次調用攔截器前,都會做一次判斷,如果攔截器是動態攔截器,就根據方法參數判斷是否要調用它,否則就直接調用 processed 跳過這個攔截器。
這也就意味着,我們在攔截器中完成攔截操作後,是需要主動的調用 ReflectiveMethodInvocation.processed方法的,這個時候就體現出了這種設計的精妙之處:

  • 允許主動中斷:只有調用 proceed 時,攔截器鏈纔會繼續往下走,否則可以直接中斷整個調用流程;
  • 可以攔截調用結果:當調用 proceed 後,實際上會形成遞歸,這使得所有的攔截器都可以獲取並處理方法的返回值;

總結

1、代理的創建時機

  • 實例化前後:依靠 InstantiationAwareBeanPostProcessor 完成,不太常見;
  • 初始化後:依靠 BeanPostProcessor 完成,如果沒有因爲循環依賴導致 bean 被提前實例化,那麼正常情況 bean 會在這時被代理;
  • 獲取早期引用時:依靠 SmartInstantiationAwareBeanPostProcessor 完成,當需要被代理的 bean 由於循環依賴導致初始化前就要被其他 bean 獲取時,會在這時被提前完成代理;

其中,後兩者最終都會通過 AbstractAutoProxyCreator.wrapIfNecessary 完成代理對象的創建。

2、通知器的獲取

當進入 wrapIfNecessary 方法後,在真正的創建代理對象前,需要通過AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean 方法獲取可應用於代理對象的通知器。
該方法的具體實現位於 AbstractAdvisorAutoProxyCreator 中:

  • 調用 findEligibleAdvisors 用於查出是否有可用的通知器;
  • findEligibleAdvisors 方法中,通過 findCandidateAdvisors 加載 spring 容器中的所有 Advisor ,在 AnnotationAwareAspectJAutoProxyCreator 中通過重寫該方法,額外加載了一些基於 AspectJ 的通知器;
  • 再調用 findAdvisorsThatCanApply 從所有的 Advisor 中篩選出可應用於當前 bean 的通知器:
    1. 如果通知器是 IntroductionAdvisor  類型,則通過通知器的 ClassFilter 進行類型匹配;
    2. 如果通知器是 PointcutAdvisor  類型,則通過通知器的 Pointcut 切點中的 ClassFilterMethodMatcher 分別對類型和類中的方法進行匹配。其中,若 MethodMatcher 類型爲 IntroductionAwareMethodMatcher ,則支持同時根據方法與其類型進行匹配;
    3. 如果通知器不是上述兩者,則認爲其必定可應用與當前 bean;

經過上述流程後若當前 bean 沒有任何可用的通知器,則說明其無需代理,否則需要通過通知器進行代理增強。

3、代理前的準備

獲得可用的通知器後,將會調用 createProxy 方法真正的進入創建代理對象的邏輯中。

  • 創建一個 ProxyFactory 用於後續創建代理對象;
  • 嘗試推斷代理對象的類型:
    1. proxyFactory 設置了 proxyTargetClass 標誌爲 true,則說明要使用目標類(target class)作爲代理的基礎。在這種情況下,如果目標類是 JDK 動態代理的代理類(比如 Annotation)或者是 Lambda 表達式生成的匿名內部類,則需要遍歷目標類的接口,將這些接口添加到代理工廠中,以保證代理對象具備這些接口的方法;
    2. 如果 proxyFactoryproxyTargetClass 標誌沒有設置爲 true,則執行下面的邏輯。這表示沒有顯式要求使用目標類作爲代理基礎,則:
      a.應該使用目標類作爲代理基礎,則將 proxyTargetClass 標誌設置爲 true ,即需要進行 CGLib 代理;
      b.不滿足使用目標類作爲代理基礎的條件,則調用 evaluateProxyInterfaces 方法,根據目標類的接口信息,將適合的接口添加到代理工廠中;
  • 適配通知器:在這一步,大部分的 Advisor 都以及被蒐集到了,不過仍有一些通知器需要在 buildAdvisors 方法中進行適配或者特殊的處理:
    1. 收集通用通知器:處了在容器中註冊的通知器外,有另一部分通用通知器直接通過直接在 AbstractAutoProxyCreator 中登記 beanName 的方法設置,此時需要根據 beanName 將其從容器中取出;
    2. 適配通知器:此時,已收集的通知器中混有多種類型的對象,因此需要通過 AdvisorAdapterRegistry.wrap **方法將其中非 Advisor 對象進行適配:
      1. 如果已經是 Advisor 了,就直接返回;
      2. 如果不是 Advisor ,那必須是 Advice ,否則直接拋異常;
      3. 如果它是 MethodInterceptor ,那就將其適配爲 DefaultPointcutAdvisor
      4. 如果是其他類型的 Advice ,就調用適配器鏈,找到一個支持處理這個攔截器的 AdvisorAdapter 去對它做適配;

4、創建代理對象

  • 當在 ProxyFactory 中配置好了代理對象的類型、需要實現的接口類型、需要應用的通知器及其他配置後;
  • ProxyFactory 將會在 createAopProxy 方法中獲取一個AopProxyFactory (默認爲 DefaultAopProxyFactory);
  • 接着調用 DefaultAopProxyFactorycreateAopProxy 方法,根據情況去創建一個 AopProxy 對象:
    1. 如果需要基於目標類代理,那麼就使用 CGLib 代理,返回一個 ObjenesisCglibAopProxy
    2. 如果需要基於接口代理,那麼使用 JDK 的動態代理,返回一個 JdkDynamicAopProxy
  • 接着我們調用 AopProxygetProxy 方法,該方法將會真正的創建一個代理對象。

5、方法代理

對於 JDK 動態代理來說,用於生成代理的 InvocationHandler 即爲 JdkDynamicAopProxy 本身,當我們調用代理對象的方法時,將會統一經過 invoke 方法。
其中,根據方法類型又分爲三種類型:

  • equalshashCode 方法:若兩方法沒有在接口中重新定義,則直接按 JdkDynamicAopProxy 去進行比較/獲取哈希值;
  • 如果方法是 DecoratingProxyAdvised 接口中聲明的方法,則直接通過當前代理對象內部持有的相應實例進行調用;
  • 如果是普通方法,則在調用前後一次調用通知器中的 Advice 增強邏輯;

其中,對於普通方法,在首次調用 invoke 的時候,將會:

  • 通過內部持有的 AdvisedSupport 對象(即 Advised 的默認實現)的 getInterceptorsAndDynamicInterceptionAdvice 方法獲取相應的方法攔截器;
  • 然後 AdvisedSupport 將會通過內部的 AdvisorChainFactory (默認爲 DefaultAdvisorChainFactory)的 getInterceptorsAndDynamicInterceptionAdvice 方法創建方法攔截器鏈;
  • DefaultAdvisorChainFactory 中,將會:
    1. 先取出 AdvisedSupport 中存放的所有可應用於當前 bean 的通知器,然後遍歷它們:
      1. 如果當前的 Advisor 是一個 PointcutAdvisor,即基於切點的通知器,那麼根據其持有的切點 Pointcut 中的 ClassFilterMethodMatcher 進行匹配;
      2. 如果當前的 Advisor 是一個IntroductionAdvisor,即引介增強器,那麼根據類過濾器的匹配規則判斷是否需要將它添加到攔截器鏈中;
      3. 如果當前的 Advisor 不是上述兩種類型,直接將它的攔截器數組添加到攔截器鏈中;
    2. 在獲得的可用的通知器後,通過 AdvisorAdapterRegistry.getInterceptors (此處的適配器註冊表在上文也用於適配 Advisor)方法將其全部適配爲 MethodInterceptor
  • 通過 DefaultAdvisorChainFactory 獲取方法攔截器鏈後,將會將攔截器鏈與要增強的代理方法封裝爲一個方法調用對象 MethodInvocation (默認爲 ReflectiveMethodInvocation);
  • 然後調用 MethodInvocation.processed 方法,此時將會調用鏈首的攔截器,接着攔截器再繼續調用 processed 方法,遞歸此步驟,直到整個調用鏈完成或者中斷爲止;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章