AOP原始碼解析之二-建立AOP代理前傳,獲取AOP資訊

程式設計師田同學發表於2022-03-21

AOP原始碼解析之二-建立AOP代理前傳,獲取AOP資訊。

上篇文章對AOP的基本概念說清楚了,那麼接下來的AOP還剩下兩個大的步驟獲取定義的AOP資訊,生成代理物件扔到beanFactory中。

本篇文章重點對前半部分,如何獲取到AOP資訊的過程解讀。

在Spring的核心方法Refresh方法中,aop是在

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

開始切入的,該文章就開始深入這個方法進行解析。

@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		// 檢測是否被解析過
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			// hasInstantiationAwareBeanPostProcessors()是來判斷容器中是否有InstantiationAwareBeanPostProcessor的實現bean
			// AOP切面後置處理器AspectJAwareAdvisorAutoProxyCreator就實現了InstantiationAwareBeanPostProcessor介面
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					// 執行實現了InstantiationAwareBeanPostProcessor介面的BeanPostProcessor中的前置處理方法postProcessBeforeInstantiation方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						// 執行實現了InstantiationAwareBeanPostProcessor介面的BeanPostProcessor中的後置處理方法postProcessAfterInitialization方法
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

見名知意,resolveBeforeInstantiation(執行初始化前方法),這一步主要判斷一下工廠中是否有 InstantiationAwareBeanPostProcessor 的實現bean。InstantiationAwareBeanPostProcessor 應該是AOP最核心的介面了。

我們看一下InstantiationAwareBeanPostProcessor 的繼承結構。

image-20220321090152628

我們詳細的說下InstantiationAwareBeanPostProcessor 這個介面。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

   Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

   boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

   PropertyValues postProcessPropertyValues(
         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}

它和 BeanPostProcessor 的方法非常相似,而且它還繼承了 BeanPostProcessor。

下面是 BeanPostProcessor 中的兩個方法:

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

發現沒有,InstantiationAwareBeanPostProcessor 是 Instantiation,BeanPostProcessor 是 Initialization,它代表的是 bean 在例項化完成並且屬性注入完成,在執行 init-method 的前後進行作用的。

而 InstantiationAwareBeanPostProcessor 的執行時機要前面一些,我們回到refresh方法的doCreateBean中看一下。

image-20220321091420346

看到這讀者想必對於aop的執行時機已經模模糊糊的心裡有個大概了。

我們定義的環繞通知,建立代理一定是在postProcessBeforeInitialization完成的。

我們的重點就是看看postProcessBeforeInitialization的方法中的通知怎麼獲取,怎麼建立代理物件的進行詳細的解讀。

本文先對前半部分解讀。

我們繼續看postProcessBeforeInitialization有哪些實現類。

image-20220321092132443

我們重點看AbstractAutoProxyCreator的實現類。

@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 1.判斷當前bean是否需要被代理,如果需要則進行封裝
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				//1.判斷當前bean是否需要被代理,如果需要則進行封裝
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

如果需要代理執行繼wrapIfNecessary方法。

//這個方法將返回代理類
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 1.判斷當前bean是否在targetSourcedBeans快取中存在(已經處理過),如果存在,則直接返回當前bean
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 2.在advisedBeans快取中存在,並且value為false,則代表無需處理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 3.bean的類是aop基礎設施類 || bean應該跳過,則標記為無需處理,並返回
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 4.獲取當前bean的Advices和Advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 5.如果存在增強器則建立代理
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 建立代理...建立代理...建立代理...
			// 5.1 建立代理物件:這邊SingletonTargetSource的target屬性存放的就是我們原來的bean例項(也就是被代理物件),
			// 用於最後增加邏輯執行完畢後,通過反射執行我們真正的方法時使用(method.invoke(bean, args))
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 5.2 建立完代理後,將cacheKey -> 代理類的class放到快取
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		// 6.標記為無需處理
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

4.1 我們先檢視第一條主線,獲取當前bean的Advices和Advisors

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

		// 1.找到符合條件的Advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			// 2.如果沒有符合條件的Advisor,則返回null
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

注:Advisors即是aop的環繞通知。

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 1.查詢所有的候選Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 2.從所有候選的Advisor中找出符合條件的
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		// 3.擴充套件方法,留個子類實現
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// 4.對符合條件的Advisor進行排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

這一步所做的事很簡單,就是查詢所有候選的Advisor,但是呼叫鏈路特別的長,如果將這些徹底搞明白,還是需要耗費一番功夫的,讀者可以選擇深入程度。

1、尋找可用的Advisor

public List<Advisor> findAdvisorBeans() {
		// Determine list of advisor bean names, if not cached already.
		// 1.確認advisor的beanName列表,優先從快取中拿
		String[] 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!
			//  1.1 如果快取為空,則獲取class型別為Advisor的所有bean名稱
			advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);
			this.cachedAdvisorBeanNames = advisorNames;
		}
		if (advisorNames.length == 0) {
			return new ArrayList<>();
		}

		// 2.遍歷處理advisorNames
		List<Advisor> advisors = new ArrayList<>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
				// 2.1 跳過當前正在建立的advisor
				if (this.beanFactory.isCurrentlyInCreation(name)) {
					if (logger.isTraceEnabled()) {
						logger.trace("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					try {
						// 2.2 通過beanName獲取對應的bean物件,並新增到advisors
						advisors.add(this.beanFactory.getBean(name, Advisor.class));
					}
					catch (BeanCreationException ex) {
						Throwable rootCause = ex.getMostSpecificCause();
						if (rootCause instanceof BeanCurrentlyInCreationException) {
							BeanCreationException bce = (BeanCreationException) rootCause;
							String bceBeanName = bce.getBeanName();
							if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
								if (logger.isTraceEnabled()) {
									logger.trace("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;
					}
				}
			}
		}
		// 3.返回符合條件的advisor列表
		return advisors;
	}
/**
 * 找到符合條件的Advisor
 * @return
 */
@Override
protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
   if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}
public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;

   // 1.如果aspectNames為空,則進行解析
   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            // 1.1 獲取所有的beanName
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            // 1.2 迴圈遍歷所有的beanName,找出對應的增強方法
            for (String beanName : beanNames) {
               // 1.3 不合法的beanName則跳過,預設返回true,子類可以覆蓋實現,AnnotationAwareAspectJAutoProxyCreator
               // 實現了自己的邏輯,支援使用includePatterns進行篩選
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               // We must be careful not to instantiate beans eagerly as in this case they
               // would be cached by the Spring container but would not have been weaved.
               // 獲取beanName對應的bean的型別
               Class<?> beanType = this.beanFactory.getType(beanName);
               if (beanType == null) {
                  continue;
               }
               // 1.4 如果beanType存在Aspect註解則進行處理
               if (this.advisorFactory.isAspect(beanType)) {
                  // 將存在Aspect註解的beanName新增到aspectNames列表
                  aspectNames.add(beanName);
                  // 新建切面後設資料
                  AspectMetadata amd = new AspectMetadata(beanType, beanName);
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     // 使用BeanFactory和beanName建立一個BeanFactoryAspectInstanceFactory,主要用來建立切面物件例項
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                     // 1.5 解析標記AspectJ註解中的增強方法*********************
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                     // 1.6 放到快取中
                     if (this.beanFactory.isSingleton(beanName)) {
                        // 如果beanName是單例則直接將解析的增強方法放到快取
                        this.advisorsCache.put(beanName, classAdvisors);
                     }
                     else {
                        // 如果不是單例,則將factory放到快取,之後可以通過factory來解析增強方法
                        this.aspectFactoryCache.put(beanName, factory);
                     }
                     // 1.7 將解析的增強器新增到advisors
                     advisors.addAll(classAdvisors);
                  }
                  else {
                     // Per target or per this.
                     if (this.beanFactory.isSingleton(beanName)) {
                        // 名稱為beanName的Bean是單例,但切面例項化模型不是單例,則拋異常
                        throw new IllegalArgumentException("Bean with name '" + beanName +
                              "' is a singleton, but aspect instantiation model is not singleton");
                     }
                     MetadataAwareAspectInstanceFactory factory =
                           new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                     // 將factory放到快取,之後可以通過factory來解析增強方法
                     this.aspectFactoryCache.put(beanName, factory);
                     // 解析標記AspectJ註解中的增強方法,並新增到advisors中
                     advisors.addAll(this.advisorFactory.getAdvisors(factory));
                  }
               }
            }
            // 1.9 將解析出來的切面beanName放到快取aspectBeanNames
            this.aspectBeanNames = aspectNames;
            return advisors;
         }
      }
   }

   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
      if (cachedAdvisors != null) {
         advisors.addAll(cachedAdvisors);
      }
      else {
         MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
         advisors.addAll(this.advisorFactory.getAdvisors(factory));
      }
   }
   // 1.10 最後返回解析出來的增強器
   return advisors;
}
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   // 1.前面我們將beanClass和beanName封裝成了aspectInstanceFactory的AspectMetadata屬性,
   // 這邊可以通過AspectMetadata屬性重新獲取到當前處理的切面類
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   // 2.獲取當前處理的切面類的名字
   String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
   // 3.校驗切面類
   validate(aspectClass);

   // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
   // so that it will only instantiate once.
   // 4.使用裝飾器包裝MetadataAwareAspectInstanceFactory,以便它只例項化一次。
   MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
         new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

   List<Advisor> advisors = new ArrayList<>();
   // 5.獲取切面類中的方法(也就是我們用來進行邏輯增強的方法,被@Around、@After等註解修飾的方法,使用@Pointcut的方法不處理)
   for (Method method : getAdvisorMethods(aspectClass)) {
      // 6.處理method,獲取增強器
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
      if (advisor != null) {
         // 7.如果增強器不為空,則新增到advisors
         advisors.add(advisor);
      }
   }

   // If it's a per target aspect, emit the dummy instantiating aspect.
   if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      // 8.如果尋找的增強器不為空而且又配置了增強延遲初始化,那麼需要在首位加入同步例項化增強器(用以保證增強使用之前的例項化)
      Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
      advisors.add(0, instantiationAdvisor);
   }

   // Find introduction fields.
   // 9.獲取DeclareParents註解
   for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }

   return advisors;
}
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
      int declarationOrderInAspect, String aspectName) {

   // 1.校驗切面類
   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

   // 2.AspectJ切點資訊的獲取(例如:表示式),就是指定註解的表示式資訊的獲取,
   // 如:@Around("execution(* com.joonwhee.open.aop.*.*(..))")
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   // 3.如果expressionPointcut為null,則直接返回null
   if (expressionPointcut == null) {
      return null;
   }

   // 4.根據切點資訊生成增強器
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
         this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

獲取到@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut定義註解資訊

@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
   // 1.查詢並返回給定方法的第一個AspectJ註解(@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut)
   // 因為我們之前把@Pointcut註解的方法跳過了,所以這邊必然不會獲取到@Pointcut註解
   AspectJAnnotation<?> aspectJAnnotation =
         AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
   // 2.如果方法沒有使用AspectJ的註解,則返回null
   if (aspectJAnnotation == null) {
      return null;
   }

   // 3.使用AspectJExpressionPointcut例項封裝獲取的資訊
   AspectJExpressionPointcut ajexp =
         new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
   // 提取得到的註解中的表示式,
   // 例如:@Around("execution(* com.joonwhee.open.aop.*.*(..))"),得到:execution(* com.joonwhee.open.aop.*.*(..))
   ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
   if (this.beanFactory != null) {
      ajexp.setBeanFactory(this.beanFactory);
   }
   return ajexp;
}
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
   // 設定要查詢的註解類
   for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
      // 查詢方法上是否存在當前遍歷的註解,如果有則返回
      AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
      if (foundAnnotation != null) {
         return foundAnnotation;
      }
   }
   return null;
}

2、獲取切點以後就需要生成增強器了。

 new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName)
/**
 * 根據切點資訊生成增強器
 * @param declaredPointcut
 * @param aspectJAdviceMethod
 * @param aspectJAdvisorFactory
 * @param aspectInstanceFactory
 * @param declarationOrder
 * @param aspectName
 */
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
      Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
      MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

   // 1.簡單的將資訊封裝在類的例項中
   this.declaredPointcut = declaredPointcut;
   this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
   this.methodName = aspectJAdviceMethod.getName();
   this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
   // aspectJAdviceMethod儲存的是我們用來進行邏輯增強的方法(@Around、@After等修飾的方法)
   this.aspectJAdviceMethod = aspectJAdviceMethod;
   this.aspectJAdvisorFactory = aspectJAdvisorFactory;
   this.aspectInstanceFactory = aspectInstanceFactory;
   this.declarationOrder = declarationOrder;
   this.aspectName = aspectName;

   // 2.是否需要延遲例項化
   if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      // Static part of the pointcut is a lazy type.
      Pointcut preInstantiationPointcut = Pointcuts.union(
            aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

      // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
      // If it's not a dynamic pointcut, it may be optimized out
      // by the Spring AOP infrastructure after the first evaluation.
      this.pointcut = new PerTargetInstantiationModelPointcut(
            this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
      this.lazy = true;
   }
   else {
      // A singleton aspect.
      this.pointcut = this.declaredPointcut;
      this.lazy = false;
      // 3.例項化增強器:根據註解中的資訊初始化對應的增強器
      this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
   }
}

經過以上長長的原始碼分析過程,就將aop的第一個大過程,獲取到我們定義的@Before、@After的方法以後,進行增強,下一步就要拿到這些獲取的資訊去建立代理物件了。

相關文章