天天看點

Spring源碼之建立AOP代理之增強器的擷取

前言

在上一篇博文中我們說到了通過自定義配置完成了對

AnnotationAwareAspectJAutoProxyCreator

類型的自動注冊,那麼這個類究竟做了什麼工作進而完成AOP的操作呢?首先我們看一下

AnnotationAwareAspectJAutoProxyCreator

的類圖結構,如圖:

Spring源碼之建立AOP代理之增強器的擷取

AOP的源碼解析操作入口

從UML類圖中我們看到`AnnotationAwareAspectJAutoProxyCreator`這個類實作了`BeanPostProcessor`接口,而實作這個`BeanPostProcessor`後,當Spring加載這個Bean時會在執行個體化之前調用器`postProcessorAfterIntialization`方法,而我們就從這裡進行分析AOP的邏輯
           
  • 首先我們先看一下它父類

    AbstractAutoProxyCreator

    postProcessorIntialization

    方法
  • 看源碼(具體實作在

    AbstractAutoProxyCreator.class

    )
/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// 根據bean的class 和 name建構出一個key  格式:beanClassName_beanName
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 如果它适合被代理,則需要指定封裝bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
}
           

在上面代碼中用到了方法

wrapIfNecessary

,進入到該函數方法的内部:

  • 看源碼(具體實作在

    AbstractAutoProxyCreator.class

    )
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;
		}
		// 給定的bean類是否是一個基礎設施類,基礎設施類不應該被代理,或者配置了指定的bean不需要代理
		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;
}
           
從上面的函數中我們可以大概看出代理的建立過程的一個雛形。當然真正的開始之前還需要一些個判斷,比如是否已經處理過或者是 是否需要跳過的bean,而真正建立代理的代碼是在`getAdvicesAndAdvisorsForBean`函數開始的。
           

** 建立代理需要兩個步驟:**

  1. 擷取增強方法或增強器;
  2. 根據擷取的增強來進行代理。

上述兩個步驟其中邏輯是十分複雜的,首先來看看擷取增強方法的邏輯實作。擷取增強的方法

getAdvicesAndAdvisorsForBean

是在

AbstractAdvisorAuroProxyCreator

中實作的,代碼如下:

  • 看源碼(具體實作在

    AbstractAdvisorAuroProxyCreator.class

    )
@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();
}
           
  • 源碼分析

主要檢視上述函數體内的

findEligibleAdvisor

方法。進入該方法實作也在

AbstractAdvisorAuroProxyCreator.class

  • 看源碼(具體實作在

    AbstractAdvisorAutoProxyCreator.class

    )
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
}
           
  • 源碼分析

通過

findEligbleAdvisor

的具體實作我們看到,對于指定bean的增強方法的擷取包含了兩個步驟:

  1. 擷取所有增強,
  2. 尋找所有增強中 對于bean的增強并應用(也就是尋找比對bean的增強器)。

函數中的

findCandidateAdvisors

findAdvisorsThatCanApply

便是做了這兩件事

當然如果這個方法沒有找到增強器,

getAdvicesAndAdvisorsForBean

就會傳回一個

DO_NOT_PROXY

,DO_NOT_PROXY時已經定義好的null

擷取增強器

從一開始我們分析的就是基于注解進行的AOP,是以對于

findidateAdvisors

的實作是由

AnnotationAwareAspectJAutoProxyCreator

類的

findCandidateAdvisors

方法完成的。

  • 看源碼(具體實作在

    AnnotationAwareAspectJAutoProxyCreator.class

    )
@Override
protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		// 當使用注解方式配置AOP的時候并不是對xml配置檔案的支援進行了丢棄
		// 在這裡調用父類加載配置檔案中的AOP聲明
		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;
}
           
  • 源碼解析:

首先我們先看一下

AnnotationAwareAspectJAutoProxyCreator.class

這個類的UML,

在上圖中我們看到AnnotationAwareAspectJAutoProxyCreator間接繼承了AbstractAdvisorsAutoProxyCreator,在實作擷取增強方法中保留了父類的擷取配置檔案中定義的增強,是由

List<Advisor> advisors = super.findCandidateAdvisors();

實作;

此外同時還添加了擷取Bean的注解增強的功能,是由

this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

這個方法實作的

Spring擷取增強器(增強方法)的解析思路大緻如下:

  1. 擷取所有的beanName,這一步驟中所有的beanFactory中注冊的Bean都會被提取出來。
  2. 周遊所有的beanName,并找出使用**@Aspect注解聲明的類,并進行進一步處理。
  3. 對于标記Aspect注解的類進行增強器的提取。
  4. 将提取結果加入緩存

接下來我們分析一下以上步驟的實作,首先

  • 看this.aspectJAdvisorsBuilder.buildAspectJAdvisors()源碼的實作(具體實作在

    BeanFactoryAspectJAdvisorsBuilder.class

    )
public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
					// 擷取所有的beanName
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					// 循環所有的beanName擷取 擷取聲明AspectJ的類,找出對應的增強方法
					for (String beanName : beanNames) {
						// 不合法的bean 則略過,由子類定義規則傳回true
						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.
						// 擷取對應的bean Class類型
						Class<?> beanType = this.beanFactory.getType(beanName, false);
						if (beanType == null) {
							continue;
						}
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								// 解析标記AspectJ注解的增強方法
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									// 将增強器加入緩存 下次可以直接取
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name \'" + beanName +
											"\' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					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));
			}
		}
		return advisors;
}
           
執行到此,Spring就完成了Advisor的提取,在上面的步驟中**最繁雜最重要**的就是增強**器的擷取**,而這一步又交給了`getAdvisors`方法去實作的。(`this.advisorFactory.getAdvisors(factory);`)
           
  • 首先看this.advisorFactory.isAspect(beanType)源碼(具體實作在

    AbstractAspectJAdvisorFactory.class

    )
@Override
public boolean isAspect(Class<?> clazz) {
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}

private boolean hasAspectAnnotation(Class<?> clazz) {
		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
           

緊接着再檢視一下

findAnnotation

方法:

@Nullable
public static <A extends Annotation> A findAnnotation(Class<?> clazz, @Nullable Class<A> annotationType) {
		if (annotationType == null) {
			return null;
		}

		// Shortcut: directly present on the element, with no merging needed?
		if (AnnotationFilter.PLAIN.matches(annotationType) ||
				AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
			// 判斷此Class 是否存在Aspect.class注解
			A annotation = clazz.getDeclaredAnnotation(annotationType);
			if (annotation != null) {
				return annotation;
			}
			// For backwards compatibility, perform a superclass search with plain annotations
			// even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
			Class<?> superclass = clazz.getSuperclass();
			if (superclass == null || superclass == Object.class) {
				return null;
			}
			return findAnnotation(superclass, annotationType);
		}

		// Exhaustive retrieval of merged annotations...
		return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
				.get(annotationType).withNonMergedAttributes()
				.synthesize(MergedAnnotation::isPresent).orElse(null);
}
           

這裡如果bean存在Aspect.class注解,那麼就可以擷取此bean的增強器了,接下來我們回到BeanFactoryAspectJAdvisorsBuilder類中檢視this.advisorFactory.getAdvisors(factory);方法。

  • 看源碼(具體實作在

    ReflectiveAspectJAdvisorFactory.class

    )
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		// 擷取标記AspectJ的類
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		// 擷取标記AspectJ的name
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		validate(aspectClass);

		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
		// so that it will only instantiate once.
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();
		// 對于aspect class的每一個帶有注解的方法進行循環(除了@Pointcut注解的方法除外),取得Advisor,并添加到集合裡
		// 這裡應該取到的是Advice,然後取得我們自定義的切面類中的PointCut,組合成Advisor
		for (Method method : getAdvisorMethods(aspectClass)) {
			// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
			// to getAdvisor(...) to represent the "current position" in the declared methods list.
			// However, since Java 7 the "current position" is not valid since the JDK no longer
			// returns declared methods in the order in which they are declared in the source code.
			// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
			// discovered via reflection in order to support reliable advice ordering across JVM launches.
			// Specifically, a value of 0 aligns with the default value used in
			// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
			// 将類中的方法封裝成Advisor
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		// If it\'s a per target aspect, emit the dummy instantiating aspect.
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

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

		return advisors;
}
           
普通增強器的擷取

普通增強其的擷取邏輯通過

getAdvisor

方法實作,實作步驟包括對切點的注解的擷取以及根據注解資訊生成增強。

首先我們看一下 getAdvisorMethods(aspectClass)這個方法,它很巧妙的使用接口定義一個匿名回調,把帶有注解的Method都取出來,放到集合裡。

  • 看源碼
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		List<Method> methods = new ArrayList<>();
		ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
		if (methods.size() > 1) {
			methods.sort(adviceMethodComparator);
		}
		return methods;
}
           

然後在看一下函數體内的

doWithMethods

方法 具體實作在ReflectionUtils中

public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
		// Keep backing up the inheritance hierarchy.
		Method[] methods = getDeclaredMethods(clazz, false);
		for (Method method : methods) {
			if (mf != null && !mf.matches(method)) {
				continue;
			}
			try {
				mc.doWith(method);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access method \'" + method.getName() + "\': " + ex);
			}
		}
		if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
			doWithMethods(clazz.getSuperclass(), mc, mf);
		}
		else if (clazz.isInterface()) {
			for (Class<?> superIfc : clazz.getInterfaces()) {
				doWithMethods(superIfc, mc, mf);
			}
		}
}
           

然後我們在回到ReflectiveAspectJAdvisorFactory.class類中擷取普通增強器的getAdvisor方法

  • 看源碼(具體實作在

    ReflectiveAspectJAdvisorFactory.class

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

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		// 擷取Pointcut資訊 主要是擷取Pointcut表達式
		// 把Method對象也傳進去的目的是,比較Method對象上的注解,是不是下面的注解的其中的一個,
		// 如果不是傳回null;如果是就把Pointcut内容包裝傳回
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}

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

切點資訊的擷取

所謂擷取切點資訊就是指注解的表達式資訊的擷取,如@Before("test()")。

  • 看源碼(具體在

    ReflectiveAspectJAdvisorFactory.class

    )
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
		// 擷取方法上的注解,比較Method對象上的注解是不是下面其中的一個,如果不是傳回null
		// 被比較的注解:Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// 使用AspectJExpressionPointcut執行個體封裝擷取的資訊
		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
		// 提取到注解中的表達式并設定進去
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		if (this.beanFactory != null) {
			ajexp.setBeanFactory(this.beanFactory);
		}
		return ajexp;
}
           

我們再看一下上面使用到的

findAspectJAnnotationOnMethod

方法的實作

  • 看源碼(具體是現在

    AbstractAspectJAdvisorFactory.class

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

小插曲:注意一下上面的

ASPECTJ_ANNOTATION_CLASSES

變量,它設定了查找的注解類:

  • 源碼
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
           

再次回到findAspectJAnnotationOnMethod方法的實作,裡面使用了

findAnnotation

方法,跟蹤該方法

  • 看源碼(具體實作在

    AbstractAspectAdvisorFacrory.class

    )
/**
	 * 擷取指定方法上的注解 并使用AspectAnnotation進行封裝
	 * @param method
	 * @param toLookFor
	 * @param <A>
	 * @return
	 */
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
		A result = AnnotationUtils.findAnnotation(method, toLookFor);
		if (result != null) {
			return new AspectJAnnotation<>(result);
		}
		else {
			return null;
		}
}
           

此方法的功能是擷取指定方法上的注解并使用AspectJAnnotation封裝。

根據切點資訊擷取增強類

所有的增強都由Advisor實作類InstantiationModelAwarePointCutAdvisorImpl進行統一封裝。我們簡單看一下其構造函數:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		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;
			// 初始化Advice
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
}
           
通過對上面的構造函數的分析,發現封裝過程隻是簡單的将資訊封裝在類的執行個體中,所有的資訊都是單純的複制。在執行個體初始化的工程中還完成了對于增強器的初始化。因為不同的增強所展現的邏輯是不同的,比如`@Before("test()")`和`@After("test()")`标簽的不同就是增強器的位置不同,是以需要不同的增強器來完成不同的邏輯,而根據注解中的資訊初始化對應的增強器就是在`instantiateAdvice`函數中實作的,繼續跟蹤源碼:
           
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
}
           
接下來再繼續跟蹤getAdvice函數的具體實作
           
  • 看源碼(具體實作在

    ReflectiveAspectJAdvisorFactory.class

    )
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it\'s an AspectJ-annotated class
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method \'" + candidateAdviceMethod + "\' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;

		// 根據不同的注解類型封裝不同的增強器
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut \'" + candidateAdviceMethod.getName() + "\'");
				}
				return null;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method: " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
}
           

前置增強

從上面的函數中我們看到,Spring會根據不同的注解生成不同的增強器,具體表現在了

switch (aspectJAnnotation.getAnnotationType())

,根據不同的類型來生成。例如在AtBefore會對應AspectJMethodBeforeAdvice,早AspectJMethodBeforeAdvice中完成了增強邏輯,

并且這裡的**AspectJMethodBeforeAdvice**最後被擴充卡封裝成**MethodBeforeAdviceInterceptor**,
           
如何被封裝的 這有機再在分析。

我們先看一下MethodBeforeAdviceInterceptor的代碼

  • 看源碼
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

	private final MethodBeforeAdvice advice;


	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}


	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

}
           

其中上述代碼的

MethodBeforeAdvice

代表的前置增強的

AspectJMethodBeforeAdvice

,根據

before

方法來到這個類。

  • 看源碼(具體實作在

    AspectJMethodBeforeAdvice.java

    )
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
		// 直接調用增強方法
		invokeAdviceMethod(getJoinPointMatch(), null, null);
}
           

繼續跟蹤函數體内的

invokeAdviceMethod

方法

  • 看源碼(具體實作在

    AbstractAspectJAdvice.java

    )
protected Object invokeAdviceMethod(
			@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
			throws Throwable {

		return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
           

接着繼續根據函數體内的

invokeAdviceMethodWithGivenArgs

方法,

  • 看源碼(具體實作在

    AbstractAspectJAdvice.java

    )
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			// 通過反射調用AspectJ注解類中的增強方法
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
}
           

invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是對前置增強的方法,在這裡實作了調用。

簡單總結:

前置通知的大緻過程是在攔截器鍊中放置MethodBeforeAdviceInterceptor,而在MethodBeforeAdvivceInterceptor中又放置了AspectJMethodBeforeAdvice,并在調用invoke時首先串聯調用。

後置增強

相比前置增強略有不同,後置增強沒有提供中間的類,而是直接在攔截器中使用過了中間的

AspectJAfterAdvice

,也就是直接實作了

MethodInterceptor

  • 看源碼(AspectJAfterAdvice.java)
public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	public AspectJAfterAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			// 激活增強方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

	@Override
	public boolean isBeforeAdvice() {
		return false;
	}

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

}
           

其他的幾個增強器,下次具體來看

尋找比對的增強器
前面的函數中已經完成了所有增強器的解析,也就是講解完了關于`findCandidateAdvisors`方法;但是對于所有增強器來講,并不一定都适用于目前的bean,還要取出适合的增強器,也就是滿足我們配置的通配符的增強器,具體實作在`findAdvisorsThatCanAply`中,我們需要回到最初的**AbstractAdvisorAuroProxyCreator**類中,然後進入到findEligibleAdvisors函數内的**findAdvisorsThatCanAply**方法的實作:
           
  • 看源碼(

    AbstractAdvisorAuroProxyCreator.java

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

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			// 過濾已經得到的advisors
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
}
           

繼續跟蹤

findAdvisorsThatCanApply

方法:

  • 看源碼(

    AOPUtils.java

    )
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;
			}
			// 對于普通bean的 進行處理
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
}
           

findAdvisorsThatCanApply函數的主要功能時尋找增強器中适用于目前class的增強器。引介增強與普通增強的處理是不一樣的,是以分開處理。而對于真正的比對在

canApply

中實作。

接着跟蹤

canApply

方法

  • 看源碼(AopUtils.java)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		// 通過Pointcut的條件判斷此類是否比對
		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) {
			// 反射擷取類中所有的方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				// 根據比對原則判斷該方法是否能比對Pointcut中的規則,如果有一個方法比對則傳回true
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
}
           
  • 源碼分析

首先會判斷bean是否滿足切點的規則,如果能滿足,則擷取bean的所有方法,判斷是否有方法能夠比對規則,有方法比對規則就代表Advisor能作用于該bean,該方法就會傳回true,然後

findAdvisorsThatCanApply

函數就會将Advisor加入到eligibleAdvisors中。

最後我們以注解的規則來看一下bean的method是怎樣比對Pointcut中的規則的
  • 看源碼(

    AnnotationMethodMatcher.java

    )
@Override
public boolean matches(Method method, Class<?> targetClass) {
		if (matchesMethod(method)) {
			return true;
		}
		// Proxy classes never have annotations on their redeclared methods.
		if (Proxy.isProxyClass(targetClass)) {
			return false;
		}
		// The method may be on an interface, so let\'s check on the target class as well.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		return (specificMethod != method && matchesMethod(specificMethod));
	}

	private boolean matchesMethod(Method method) {
		// 可以看出判斷該Advisor是否使用于bean中的method,隻需看method上是否有Advisor的注解
		return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
				method.isAnnotationPresent(this.annotationType));
}
           

至此:在後置處理器中找到了所有比對Bean中的增強器,