Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator

Spring AOP 源碼解析系列,建議你們按順序閱讀,歡迎討論spring

  1. Spring源碼-AOP(一)-代理模式
  2. Spring源碼-AOP(二)-AOP概念
  3. Spring源碼-AOP(三)-Spring AOP的四種實現
  4. Spring源碼-AOP(四)-ProxyFactory
  5. Spring源碼-AOP(五)-ProxyFactoryBean
  6. Spring源碼-AOP(六)-自動代理與DefaultAdvisorAutoProxyCreator
  7. Spring源碼-AOP(七)-整合AspectJ

框架存在的意義,簡單來講就是將複雜的底層實現封裝起來,並提供便捷的外部接口供用戶使用。對於Spring AOP而言,不管是ProxyFactory仍是ProxyFactoryBean,都不能知足實際業務中複雜的應用,用戶不可能對每一個使用AOP代理的類進行配置。這時經過必定規則自動發現和代理天然應運而生。在spring-aop工程的autoproxy目錄構成了Spring AOP自動代理的基礎,AbstractAutoProxyCreator是自動代理實現的抽象基類,BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator則是Spring提供的兩個實現。數組

自動代理的實現原理同ProxyFactoryBean中使用FactoryBean擴展不一樣,而是經過BeanPostProcessor擴展對Bean對象的建立過程進行控制來實現AOP代理。抽象基類AbstractAutoProxyCreator實現了BeanPostProcessor的子接口SmartInstantiationAwareBeanPostProcessor。先來了解下這個子接口。緩存

1.擴展接口SmartInstantiationAwareBeanPostProcessor

咱們常說起的BeanPostProcessor擴展並非只有BeanPostProcessor一個接口,而是由其造成的多層接口體系,對Bean對象在IOC容器的建立過程的各個節點擴展造成的體系。這裏只展現下SmartInstantiationAwareBeanPostProcessor的類結構。app

輸入圖片說明

BeanPostProcessor框架

  • postProcessBeforeInitialization 初始化前擴展(執行init-method前)
  • postProcessAfterInitialization 初始化後擴展(執行init-method後)

InstantiationAwareBeanPostProcessoride

  • postProcessBeforeInstantiation 對象實例化前擴展
  • postProcessAfterInstantiation 對象實例化後擴展
  • postProcessPropertyValues 屬性依賴注入前擴展

SmartInstantiationAwareBeanPostProcessor函數

  • predictBeanType 預測bean的類型,在beanFactory的getType時被調用
  • determineCandidateConstructors 對象實例化時決定要使用的構造函數時被調用
  • getEarlyBeanReference 循環依賴處理時獲取Early對象引用時被調用

而對於Spring AOP的自動代理,處理的階段有兩個,對象實例化前擴展和初始化後擴展。post

2.自動代理基類AbstractAutoProxyCreator

在對象實例化前(postProcessBeforeInstantiation)的擴展中,主要對配置了customTargetSourceCreators屬性的狀況進行處理,而默認的處理都是在初始化後(postProcessAfterInitialization)擴展裏執行的。ui

對象實例化前postProcessBeforeInstantiation

所謂的customTargetSourceCreators屬性是在AbstractAutoProxyCreator中的一個TargetSourceCreator數組,用來對代理對象target的封裝類TargetSource的生成進行自定義。spring內置的TargetSourceCreator有兩個:LazyInitTargetSourceCreator和QuickTargetSourceCreator。this

  • LazyInitTargetSourceCreator:建立的代理對象並無初始化,直到第一次調用時才進行初始化

  • QuickTargetSourceCreator:根據beanName的不一樣前綴建立三種經常使用的TargetSource類型(bean必須爲多例)

    1. CommonsPoolTargetSource:池化TargetSource,每次執行方法時從池中取代理對象,執行完方法再返回池中
    2. ThreadLocalTargetSource:線程級的TargetSource
    3. PrototypeTargetSource:多例TargetSource,每次執行方法建立新的代理對象,執行完銷燬該對象

來看下核心代碼

if (beanName != null) {
	// 獲取自定義TargetSource
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		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;
	}
}

第一步獲取定義TargetSource,即遍歷全部自定義TargetSourceCreator,調用getTargetSource方法返回TargetSource。

protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
	// We can't create fancy target sources for directly registered singletons.
	if (this.customTargetSourceCreators != null &&
			this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
		for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
			TargetSource ts = tsc.getTargetSource(beanClass, beanName);
			if (ts != null) {
				// Found a matching TargetSource.
				if (logger.isDebugEnabled()) {
					logger.debug("TargetSourceCreator [" + tsc +
							" found custom TargetSource for bean with name '" + beanName + "'");
				}
				return ts;
			}
		}
	}

	// No custom TargetSource found.
	return null;
}

第二步獲取攔截器由子類實現,根據不一樣的方式獲取當前bean的攔截器,在後文以子類DefaultAdvisorAutoProxyCreator爲例詳細介紹。

第三步建立代理對象,經過建立ProxyFactory的方式完成,原理細節見ProxyFactory,來簡單看下它的實現。

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

	ProxyFactory proxyFactory = new ProxyFactory();
	// copy代理配置,如proxyTargetClass,exposeProxy等
	proxyFactory.copyFrom(this);

	// proxyTargetClass=false時
	if (!proxyFactory.isProxyTargetClass()) {
		// 再次確認是否要代理類對象
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		// 不須要則獲取其代理接口集合
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	// 將全部攔截器封裝成Advisor
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	for (Advisor advisor : advisors) {
		proxyFactory.addAdvisor(advisor);
	}

	proxyFactory.setTargetSource(targetSource);
	// 擴展點,支持子類對ProxyFacory擴展
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}
	
	// 建立代理對象
	return proxyFactory.getProxy(getProxyClassLoader());
}

能夠說邏輯很是清晰,最後使用ProxyFactory建立代理對象也是使用ProxyFactory統一的API。若是最終返回的代理對象不爲空,則直接返回代理對象,再也不執行IOC中的對象屬性注入和初始化等操做了。

初始化後(postProcessAfterInitialization)

若是並無設置自定義TargetSourceCreator,代理對象就會在原始對象初始化完成後建立。

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

wrapIfNecessary方法執行代理的核心操做。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	// AOP體系的子類不被代理(Advisor,Advice等)
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// 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;
}

實現過程基本同以前的一直,由子類返回攔截器集合,建立ProxyFactory對象進行代理。

3.默認自動代理類DefaultAdvisorAutoProxyCreator

在基類AbstractAutoProxyCreator中經過BeanPostProcessor擴展的方式,使得bean在建立過程當中完成被代理。代理的框架已有AbstractAutoProxyCreator基本完成,留給子類的是獲取攔截器getAdvicesAndAdvisorsForBean方法的具體實現。咱們以DefaultAdvisorAutoProxyCreator爲例,瞭解下Spring AOP是如何完成自動發現和過濾切面的。

DefaultAdvisorAutoProxyCreator的獲取攔截器實現其實由其抽象基類AbstractAdvisorAutoProxyCreator實現。

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

實際操做有findEligibleAdvisors執行

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 尋找全部Advisor候選者
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// 獲取匹配當前bean的Advisor
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		// 對Advisor排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

主要過程分爲兩步,第一步尋找全部Advisor候選者,即自動發現切面,第二部篩選當前bean的Advisor。

findCandidateAdvisors由BeanFactoryAdvisorRetrievalHelper幫助類執行,原理就是從BeanFactory及其全部父級BeanFactory中尋找類型爲Advisor的類,並執行getBean實例化。

public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	String[] advisorNames = null;
	synchronized (this) {
		advisorNames = this.cachedAdvisorBeanNames;
		if (advisorNames == null) {
			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the auto-proxy creator apply to them!
			// 尋找Advisor類型的bean
			advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);
			this.cachedAdvisorBeanNames = advisorNames;
		}
	}
	if (advisorNames.length == 0) {
		return new LinkedList<Advisor>();
	}

	List<Advisor> advisors = new LinkedList<Advisor>();
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					// getBean實例化
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					Throwable rootCause = ex.getMostSpecificCause();
					if (rootCause instanceof BeanCurrentlyInCreationException) {
						BeanCreationException bce = (BeanCreationException) rootCause;
						if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
							if (logger.isDebugEnabled()) {
								logger.debug("Skipping advisor '" + name +
										"' with dependency on currently created bean: " + ex.getMessage());
							}
							// Ignore: indicates a reference back to the bean we're trying to advise.
							// We want to find advisors other than the currently created bean itself.
							continue;
						}
					}
					throw ex;
				}
			}
		}
	}
	return advisors;
}

findAdvisorsThatCanApply篩選Advisor是由AopUtils類實現。對不一樣類型的Advisor進行不一樣的處理,如IntroductionAdvisor和PointcutAdvisor。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
	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;
		}
		// 匹配Advisor是否適用當前bean
		if (canApply(candidate, clazz, hasIntroductions)) {
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

其中canApply方法執行實際的匹配操做,細節部分主要是對切入點Pointcut和bean的匹配,有興趣的能夠本身深刻研究其匹配過程。

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) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

至此也就完成了bean適用的Advisor切面的自動發現與篩選,最後由ProxyFactory完成代理建立。

4.AOP中的循環依賴

在看自動代理源碼的過程當中,忽然注意到SmartInstantiationAwareBeanPostProcessor接口中的getEarlyBeanReference方法,它是Spring處理循環依賴時返回**未建立完(只實例化未作依賴注入)**Bean的擴展。關於循環依賴能夠去Bean的循環依賴一章去詳細瞭解,這裏只作簡單的說明。

有兩個單例Bean,A和B,A中引用了B,B中引用了A。Spring對這種相互依賴作了特殊的處理,即在對象實例化後緩存一份key爲beanName的ObjectFactory,ObjectFactory中的getObject方法返回當前建立對象的引用。

// 支持單例依賴循環
if (earlySingletonExposure) {
	// 添加Early對象緩存
	addSingletonFactory(beanName, new ObjectFactory<Object>() {
		[@Override](https://my.oschina.net/u/1162528)
		public Object getObject() throws BeansException {
			return getEarlyBeanReference(beanName, mbd, bean);
		}
	});
}

這裏假設先建立A對象實例,當A進行依賴注入時,須要B對象,則會經過getBean方法建立B對象。此時A並無建立完成,但在Early緩存中存有A的引用,於是當B對象進行依賴注入A時,直接返回A對象的Early引用,從而不會形成陷入無休止的依賴注入循環中。

在getEarlyBeanReference方法中,不只只是返回對象引用,還有一個擴展點,支持SmartInstantiationAwareBeanPostProcessor接口中的getEarlyBeanReference方法對返回的對象引用進行修改。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	Object exposedObject = bean;
	if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
				// 擴展點,對Early對象進行修改
				exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				if (exposedObject == null) {
					return exposedObject;
				}
			}
		}
	}
	return exposedObject;
}

回到AOP的自動代理上,在AbstractAutoProxyCreator中實現了getEarlyBeanReference擴展

public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	if (!this.earlyProxyReferences.contains(cacheKey)) {
		this.earlyProxyReferences.add(cacheKey);
	}
	return wrapIfNecessary(bean, beanName, cacheKey);
}

這裏將標識惟一bean的cacheKey添加到earlyProxyReferences中,在以後bean的初始化中將頗有用。而後執行wrapIfNecessary返回bean的代理對象,於是若是存在循環依賴,則依賴注入的就是真正的代理對象。

在對象執行完依賴注入後,進行初始化操做,會調用初始化後擴展postProcessAfterInitialization方法,再來關注下AbstractAutoProxyCreator此方法的實現。

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 判斷early引用中是否包含cacheKey
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

它判斷了earlyProxyReferences中不包含當前bean的cacheKey纔會執行代理操做,也就是說,若是存在循環依賴時,代理對象在getEarlyBeanReference時就建立了,而在初始化後直接跳過了,返回的bean是原始的對象。

你可能會問,既然這裏返回的不是代理對象,那代理對象最後是怎樣返回的呢?

Spring在對象進行初始化後,對存在循環依賴的又作了巧妙的處理。

if (earlySingletonExposure) {
	// 若是存在循環依賴,則返回的爲代理對象
	Object earlySingletonReference = getSingleton(beanName, false);
	if (earlySingletonReference != null) {
		// 循環依賴下,通過初始化後的對象同原始對象一致
		// 於是將代理對象賦給最終返回的對象引用
		if (exposedObject == bean) {
			exposedObject = earlySingletonReference;
		}
	}
}

這裏的設計非常巧妙,須要結合依賴循環的處理,AOP對象的處理統一來理解。同時對循環依賴時,不直接緩存對象,而是經過ObjectFactory的方式有了更深的理解。有興趣的同窗能夠反覆琢磨一下。

2017/12/24更新

回頭再看這個循環依賴的點,仍是花了一點時間來回翻了下源碼才理解,所以再補充記錄下。getSingleton(beanName, false)方法,當不存在循環依賴時,會返回null,而存在循環依賴時,返回的是ObjectFactory的getEarlyBeanReference方法返回的對象。原始的bean對象通過getEarlyBeanReference方法後,可能存在SmartInstantiationAwareBeanPostProcessor處理器,在其getEarlyBeanReference方法中被改變了,好比AbstractAutoProxyCreator中會返回代理對象。而在AbstractAutoProxyCreator的實現中,使用cacheKey保證了生成的代理對象是單例的。所以當if (exposedObject == bean)判斷時會返回true,從而getBean方法返回的對象就是真正的代理對象。此時還有一個疑問,代理對象並無進行屬性的依賴注入以及init-method等的初始化啊?其實代理對象沒有必要去複製原始對象的內部結構,由於它持有原始對象的引用,而且實際調用方法是交由原始對象去處理的。

總結

Spring AOP的自動代理,它同ProxyFactoryBean採用了不一樣的擴展方式。FactoryBean的擴展思路很是清晰,在工廠ProxyFactoryBean建立完成後直接根據其配置動態生成不一樣的代理對象,適用於簡單的配置,但在ApplicationContext高級容器中,就須要經過BeanPostProcessor擴展進行更細粒度的操做,從而支持複雜的業務配置。而接下來要討論的AspectJ整合Spring的基礎實現,就來自於Spring AOP的自動代理。

相關文章
相關標籤/搜索