javascript
Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
2019獨角獸企業重金招聘Python工程師標準>>>
Spring AOP 源碼解析系列,建議大家按順序閱讀,歡迎討論
框架存在的意義,簡單來說就是將復雜的底層實現封裝起來,并提供便捷的外部接口供用戶使用。對于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的類結構。
BeanPostProcessor
- postProcessBeforeInitialization 初始化前擴展(執行init-method前)
- postProcessAfterInitialization 初始化后擴展(執行init-method后)
InstantiationAwareBeanPostProcessor
- postProcessBeforeInstantiation 對象實例化前擴展
- postProcessAfterInstantiation 對象實例化后擴展
- postProcessPropertyValues 屬性依賴注入前擴展
SmartInstantiationAwareBeanPostProcessor
- predictBeanType 預測bean的類型,在beanFactory的getType時被調用
- determineCandidateConstructors 對象實例化時決定要使用的構造函數時被調用
- getEarlyBeanReference 循環依賴處理時獲取Early對象引用時被調用
而對于Spring AOP的自動代理,處理的階段有兩個,對象實例化前擴展和初始化后擴展。
2.自動代理基類AbstractAutoProxyCreator
在對象實例化前(postProcessBeforeInstantiation)的擴展中,主要對配置了customTargetSourceCreators屬性的情況進行處理,而默認的處理都是在初始化后(postProcessAfterInitialization)擴展里執行的。
對象實例化前postProcessBeforeInstantiation
所謂的customTargetSourceCreators屬性是在AbstractAutoProxyCreator中的一個TargetSourceCreator數組,用來對代理對象target的封裝類TargetSource的生成進行自定義。spring內置的TargetSourceCreator有兩個:LazyInitTargetSourceCreator和QuickTargetSourceCreator。
-
LazyInitTargetSourceCreator:創建的代理對象并沒有初始化,直到第一次調用時才進行初始化
-
QuickTargetSourceCreator:根據beanName的不同前綴創建三種常用的TargetSource類型(bean必須為多例)
- CommonsPoolTargetSource:池化TargetSource,每次執行方法時從池中取代理對象,執行完方法再返回池中
- ThreadLocalTargetSource:線程級的TargetSource
- PrototypeTargetSource:多例TargetSource,每次執行方法創建新的代理對象,執行完銷毀該對象
來看下核心代碼
if (beanName != null) {// 獲取自定義TargetSourceTargetSource 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);}}// 將所有攔截器封裝成AdvisorAdvisor[] 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的AdvisorList<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類型的beanadvisorNames = 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 processedcontinue;}// 匹配Advisor是否適用當前beanif (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引用中是否包含cacheKeyif (!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的自動代理。
轉載于:https://my.oschina.net/u/2377110/blog/1517915
總結
以上是生活随笔為你收集整理的Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10下使用python访问vmbo
- 下一篇: Python之自动单元测试之一(unit