AOP Advisor 封装与搜集

警告
本文最后更新于 2020-11-30,文中内容可能已过时。

spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework

链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。


1 主流程

AOP是通过 BeanPostProcessor.postProcessAfterInitialization() 实现的,来到 doCreateBean() -> initializeBean(),在初始化方法执行完成后,会调用 applyBeanPostProcessorsAfterInitialization(),这里循环调用了所有 BeanPostProcessor 的 postProcessAfterInitialization(),AOP 的入口就在其中的一个实现类,也是 AbstractAutoProxyCreator 的子类实现。

在生成代理之前,spring 会根据扫描规则,搜集容器中注册的所有 Advisor 实例、并搜集通知方法(@Aspect 注解的类中的@Before、@Around等注解标识的方法),将其封装成 Advisor。然后逐个与当前 bean 实例匹配,匹配到的放入一个集合中。

来到入口方法 postProcessAfterInitialization(),源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    @Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// 如果是FactoryBean,cacheKey是 &+beanName拼接而成,如果benaName为空,则是类名称。
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				// TODO 必要时包装给定的bean,即是否有资格被代理。
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
}

如果需要生成代理(自定义切面、事务等),会调用 wrapIfNecessary()。

wrapIfNecessary() 是这么定义的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 省略无关代码...
		// TODO 重点:如果有需要增强,就创建代理对象,这里会循环此类中所有的方法,如果有增强匹配到类中的方法,就会将增强对象封装到list中。
		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// TODO 重点:创建代理对象
			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中有方法被 pointCut 匹配到,就满足条件,将对应的通知方法封装到数组中返回)
  2. 根据匹配的通知方法列表,创建代理对象。(这里会将已排序的通知方法列表,生成一个执行链,缓存起来,当代理对象方法被调用时调用回调方法的时候,会火炬传递式的调用执行链中的通知方法。JDK动态代理和cgliib封装方式大同小异,通知方法都在回调函数所在的类中作为一个成员缓存。)

2 搜集封装Advisor

2.1 搜集流程

getAdvicesAndAdvisorsForBean() 会调用到 findEligibleAdvisors()。来到这个方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//查找到所有的增强方法,封装成Advisor对象。这里查找了两种增强,一种是实现了Advisor的实例,一种是带有@Aspect注解的bean实例中定义的增强方法。
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 根据每个增强中的切点表达式,进行匹配,筛选出合适的增强实例列表。
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		// 对增强方法进行排序,可以不看。
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
}

这里分为了两步:

  1. 收集到容器中所有的增强方法、封装成 Advisor(如果本身就是 Advisor,直接返回)。
  2. 从这所有的 Advisor 中筛选出匹配当前 bean 的 Advisor 列表。

AbstractAutoProxyCreator的注册 已经知道,这里使用的是 AnnotationAwareAspectJAutoProxyCreator。

进入 findCandidateAdvisors():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    @Override
	protected List<Advisor> findCandidateAdvisors() {
		// TODO 从父类中获取,这里获取了所有注入到容器中的Advisor类型的实例。事务的增强实例,就是在这里查找的。
		// 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) {
			// TODO 将beanFactory中缓存的所有bean实例,依次校验是否带有@Aspect注解,如果有,将其中的
			//  增强方法、切点表达式等信息,封装成Advisor。advisors变量最终存储了所有切面的增强方法封装。
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}
}

看上面代码,首先,从父类中查找 Advisor列表,然后调用 buildAspectJAdvisors(),将两者结果聚合到一个列表。


先看父类中的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class BeanFactoryAdvisorRetrievalHelper {
    public List<Advisor> findAdvisorBeans() {
		String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // 从容器中获取所有的Advisor类型的额bean名称
			advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);
			this.cachedAdvisorBeanNames = advisorNames;
		}
        // 省略非关键代码...
		List<Advisor> advisors = new ArrayList<>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
                // 从beanFactory中获取所有的Advisor类型的实例,事务支持TransactionAttributeSourceAdvisor实际上就是一个Advisor。
                advisors.add(this.beanFactory.getBean(name, Advisor.class));
			}
		}
		return advisors;
	}
}

这里搜集了容器中所有 Advisor 类型的 beanName,并将其缓存。然后调用 getBean(),将其实例化。(事务的 Advisor 其实就是在这里创建的


再看子类中的代码 buildAspectJAdvisors():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class BeanFactoryAspectJAdvisorsBuilder {
    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<>();
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					for (String beanName : beanNames) {
						// 如果不是合格的beanName,则跳过
						if (!isEligibleBean(beanName)) {
							continue;
						}
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						// 判断当前beanType是否是一个切面。判断类上是否有@Aspect
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							// 创建切面元数据实例,里面封装了切面类型,切点表达式等信息。
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							// 默认就是SINGLETON
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								// TODO 获取Advisor,这里封装了当前Aspect类中的增强方法,每个增强方法都会封装成一个Advisor。
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									// 将Advisor放入到缓存中,从上面的流程获取时,会先走缓存,缓存中有,就不会遍历查找了。
									// 这个代码块使用了双检索,这块代码在spring容器启动时,只会执行一次。
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							// 省略...
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}
		// 省略...
		// 根据切面名称,从缓存中获取到指定的增强实例,封装起来返回。
		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;
	}
}

上面代码略长、主要看带有注释的地方。代码主要流程:

  1. 获取到容器中所有的 beanName,遍历。
  2. 挨个判断,如果当前类上有 @Aspect,则解析这个类中通知方法及切入点表达式等信息。
  3. 调用 getAdvisors() 获取类中所有的通知方法,将其封装成 Advisor,作为一个列表返回。
  4. 放入缓存,下次进入就不会再遍历所有 beanNames 计算,而是从缓存中获取。

重点就在 getAdvisors(),在此之前,先来看看 isAspect():

1
2
3
4
5
6
7
8
9
public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {
	public boolean isAspect(Class<?> clazz) {
		// 这里判断类型是否包含@Aspect
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}
	private boolean hasAspectAnnotation(Class<?> clazz) {
		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
	}
}

isAspect() 中的逻辑非常简单,判断当前类中是否有 @Aspect 注解(第二个条件可以忽略,判断类中是否有字段以 ajc$ 一个特殊的标识开头的)。

来到 getAdvisors():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		// 获取切面类型,切面名称
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		validate(aspectClass);
		
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();
		// 获取增强方法,并按照方法名称排序。
		for (Method method : getAdvisorMethods(aspectClass)) {
			// TODO 将增强方法封装成Advisor,并添加到advisors变量中,最终会将这个变量返回。
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}
	    // 引介,基本用不到,这里代码省略...
		return advisors;
	}
}

注意:这个方法是在一个循环中调入进来的,aspectInstanceFactory 中封装了当前遍历到的 beanName 以及 beanFactory 的信息。

  1. getAdvisorMethods(),获取到所有非切点表达式的方法,也就是不带 @PointCut 注解的方法。
  2. 遍历这些方法,getAdvisor() 将方法封装成 Advisor。

getAdvisorMethods() 源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
    private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		final List<Method> methods = new ArrayList<>();
		ReflectionUtils.doWithMethods(aspectClass, method -> {
			// Exclude pointcuts
			if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
				methods.add(method);
			}
		});
		// 先按照注解排序、如果是相同的注解,就按照方法名称排序。
		methods.sort(METHOD_COMPARATOR);
		return methods;
	}
}

排序的代码有一点绕,嵌套的 lambda 表达式,是这么定义的(可以不看,实际业务中一般一个切面类只定义一个通知方法):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
	private static final Comparator<Method> METHOD_COMPARATOR;
	static {
		Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
				new InstanceComparator<>(
						Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
				(Converter<Method, Annotation>) method -> {
					AspectJAnnotation<?> annotation =
						AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
					return (annotation != null ? annotation.getAnnotation() : null);
				});
		// 先按照注解排序、如果是相同的注解,就按照方法名称排序。
		Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
		METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
	}
}

先使用 methodNameComparator 进行排序,如果排序结果相等,再使用 methodNameComparator 进行排序。每个比较器排序前都会使用 Converter<S, T> 转换其类型。

调用 getAdvisor():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {
		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
		// 将当前方法、类型作为参数。获取PointCut对象,最重要的是从注解中获取表达式
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
		// 这里封装了切点表达式、切面类型、增强方法等信息。它是Advisor的一个实现类,最终会加入到代理实例的执行链中。
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}
}
  1. 获取到通知方法的 PointCut() 对象,如果有方法没有切点表达式,直接返回null,这种情况会被忽略,不被加入到 Advisor 列表中。
  2. 创建 Advisor 对象,封装切点表达式、通知方法等必要信息。

2.2 PointCut的获取

关于如何获取 PointCut 的,源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
	private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
		// 找到切面相关注解,并把注解信息解析出来,包装成AspectJAnnotation
		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():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {
	/** 这里定义了切面中支持的注解,前置、后置、环绕等通知类型 */
	private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
    // 步骤一
	protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
		for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
			// 循环去找注解,并把注解信息解析出来,包装成AspectJAnnotation
			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
			if (foundAnnotation != null) {
				return foundAnnotation;
			}
		}
		return null;
	}
    // 步骤二
	private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
		// 找的规则就是找注解的父注解,递归的方式去找,直到找到目标注解为止
		A result = AnnotationUtils.findAnnotation(method, toLookFor);
		if (result != null) {
			// 把注解里面对的信息解析出来,然后包装成AspectJAnnotation对象
			return new AspectJAnnotation<>(result);
		}
		else {
			return null;
		}
	}
}

从上面代码可以看到,ASPECTJ_ANNOTATION_CLASSES数组常量中,预定义了支持切点表达式的注解。如果能在当前方法上找到任何一种,就将这个切点信息封装成 AspectJAnnotation。

2.3 Advisor的初始化

这里还有一个重点,new InstantiationModelAwarePointcutAdvisorImpl 中的初始化过程。

构造函数源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
final class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
		// 切点、切面名称、通知方法名称、等等一系列信息的封装
		this.declaredPointcut = declaredPointcut;
		// 省略...

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// 省略...
		}else {
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			// TODO 重点,实例化的过程,这里封装了具体的Advice
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}
}
重点方法是 instantiateAdvice(),这里完成了 Advice 的创建。

继续向下跟踪代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
final class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		// TODO 重点getAdvice
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
	}
}

来到 getAdvice():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
		// 获取切面类
		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);
		// 查找切点表达式、五种通知增强注解。@Before等五种。
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}
		// 省略部分代码...
		AbstractAspectJAdvice springAdvice;
		// TODO 执行判断,针对不同类型的通知,封装不同类型的Advice
        //  这几个Advice的实现类要记一下。主要以是否实现MethodInterceptor来区分,有的实现了,有的没有。
		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);
		}
		// 省略...
		return springAdvice;
	}
}
注意

上面代码中,AspectJMethodBeforeAdvice 等几个Advice的实现要看一下,这里五个 Advice 实现,部分实现了MethodInterceptor。 实现了MethodInterceptor的:

  1. AspectJAroundAdvice
  2. AspectJAfterAdvice
  3. AspectJAfterThrowingAdvice

未实现MethodInterceptor的 –> 生成执行链时依赖的适配器:

  1. AspectJMethodBeforeAdvice –> MethodBeforeAdviceAdapter
  2. AspectJAfterReturningAdvice –> AfterReturningAdviceAdapter

另外还有一个未用到的Advice,也没有实现MethodInterceptor
ThrowsAdvice –> ThrowsAdviceAdapter

在生成搭理对象后,真正执行代理方法生成执行链的时候,实现了MethodInterceptor和未实现前者的,调用逻辑上有些差别。

实现了MethodInterceptor的,会直接加入到执行链,未实现的,会通过对应的适配器,调用 getInterceptor() 来获取 MethodInterceptor,然后将 MethodInterceptor 加入执行链。(这些是后话)

3 筛选出匹配的Advisor

在获取到容器中所有的通知方法封装成的 Advisor 后,会调用 findAdvisorsThatCanApply(),将 beanName 放入到一个 ThreadLocal 类型的变量中,然后调用 findAdvisorsThatCanApply() 的重载方法。调用完毕之后,会将 ThreadLocal 变量中的 beanName置空。

findAdvisorsThatCanApply() 重载方法源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public abstract class AopUtils {
    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		// 先处理IntroductionAdvisor类型的增强
		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;
			}
			// 我们自定义的切面,就会走到这里,使用已经封装的PointcutAdvisor,根据切点表达式进行匹配,具体的匹配过程,不用看。
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
}

调用 canApply(),这里进行了切点表达式与方法的匹配,如果匹配成功,将 Advisor 放入到集合中,否则就跳过。

当将所有的 Advisor 遍历完毕,最终匹配成功的 Advisor 会被筛选出来,放入到一个新的集合中,最终生成的执行链中的通知方法,就来自筛选后的 Advisor 集合(这个集合在创建代理前还有一次新增操作)。

看 canApply(),这里进行了匹配:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public abstract class AopUtils {
    // 步骤一
    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;
		}
	}
	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		// 省略...
		// 这里做了切入点表达式的匹配,匹配通过的返回true,具体的匹配过程不用看,不是重点。
		for (Class<?> clazz : classes) {
			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;
	}
}

从上面代码可以看到,PointcutAdvisor 类型的,最终会遍历类中所有的方法,根据切点表达式,进行一一匹配,如果匹配成功,返回true,否则返回false。

4 搜集容器中所有的Advisor的流程

  1. 父类调用流程:
    graph LR;
        B(findCandidateAdvisors) -->|One| C(super.findCandidateAdvisors) 
        C --> CA{findAdvisorBeans}
        CA -->|One| CAA(beanNamesForTypeIncludingAncestors)
        CA -->|Two| CAB(beanFactory.getBean)
    
    
  2. 子类调用流程:
    graph TB;
        B(findCandidateAdvisors) -->|Two| D(buildAspectJAdvisors)
        D -->|ForEach| E(beanNames)
        E --> F(isAspect) -->|true| G{getAdvisors}
        G -->|One| GA(getAdvisorMethods)
        GA --> GAA1(doWithMethods) --> GAA2("getAnnotation(method, Pointcut.class)")
        G -->|Two| GB(getAdvisor)
        GB --> GBA(getPointcut)
        GBA --> GBAA(findAspectJAnnotationOnMethod) -->|forEach| GBAA1(ASPECTJ_ANNOTATION_CLASSES)
        GBAA1 --> GBAA2(findAnnotation) --> GBAA3("new AspectJAnnotation<>(result)")