前言

本文是看了田小波博主的Spring AOP源码分析系列后自己总结整理的笔记,内容会更偏向于流程上的总结,具体源码细节并未深入研究,并且关于AOP的相关术语这里也不会再说明。

大致流程

本文将会从AOP的入口开始分析,主要涉及以下四个流程:

  1. 入口分析
  2. 筛选合适的通知器
  3. 创建代理对象
  4. 拦截器链的执行过程

入口分析

Spring是通过后置处理器BeanPostProcessor接口在init-method的前后通过切点对bean类中的方法进行匹配后织入的,这个接口是Spring提供的一个扩展接口,通过实现该接口,用户可在Bean初始化前后做一些自定义的操作:

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
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 激活Aware相关的方法

// <2> 后处理器,before
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

// <3> 激活用户自定义的 init 方法
// 对应 <bean> 标签中的 init-method 属性
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

// <2> 后处理器,after
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

Spring AOP抽象代理创建器AbstractAutoProxyCreator实现了BeanPostProcessor接口,并在Bean初始化后置处理过程中向Bean织入通知:

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
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果需要,为 Bean 生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}

// 之前已经判断过了不需要生成代理,直接返回 Bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}

// <1> 如果是基础设施类(Pointcut、Advice、Advisor 等接口的实现类),或是应该跳过的类(默认为false,由子类覆盖),
// 则不应该生成代理,此时直接返回 Bean
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 将 <cacheKey, FALSE> 键值对放入缓存中,供上面的if使用
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// <2> 为目标 Bean 查找合适的通知器(通知器持有通知)
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <3> 如果找到了合适的通知器,则为 Bean 生成代理对象,否则直接返回 Bean
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());
// 返回代理对象,此时IoC容器中 beanName 对应的 bean 是代理对象,而非原始的 bean
return proxy;
}

// 将 <cacheKey, FALSE> 键值对放入缓存中,供上面的if使用
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <4> specificInterceptors == null,直接返回 bean
return bean;
}
}

可以看出,postProcessAfterInitialization主要过程分为四步:

  1. 若Bean是AOP基础设施类型(Pointcut、Advice、Advisor 等接口的实现类),则直接返回
  2. 为目标Bean查找匹配的通知器(通知器持有通知)
  3. 如果找到了匹配的通知器,则为Bean生成代理对象,并返回该对象
  4. 否则,返回原始bean

筛选合适的通知器

上文说过,在创建代理对象前,首先要查找合适的通知器Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);,这一行代码对应着postProcessAfterInitialization的第二步,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查找合适的通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) { // 如果没有找到
return DO_NOT_PROXY; // 则返回 null
}
return advisors.toArray(); // 否则,返回找到的通知器
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 查找所有的通知器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选可应用在 beanClass 上的 Advisor,通过 ClassFilter 和 MethodMatcher
// 对目标类和方法进行匹配
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 拓展操作
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

该过程首先会查询出所有的通知器,然后再通过ClassFilterMethodMatcher对目标类和方法进行匹配,筛选出可应用到当前bean的通知器。下面分析查询出所有的通知器的过程。

查找所有通知器

这个方法在子类AnnotationAwareAspectJAutoProxyCreator中被覆写过,增加了对@Aspect注解的解析:

1
2
3
4
5
6
7
8
9
10
@Override
protected List<Advisor> findCandidateAdvisors() {
// 调用父类方法从容器中查找所有的通知器
List<Advisor> advisors = super.findCandidateAdvisors();
// 解析 @Aspect 注解,并构建通知器
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}

这两行代码分别做了两件事:

  1. 第一步从容器中获取所有类型为Advisor的bean
  2. 第二步获取容器中所有beanName以及每个beanName对应的bean类型,遍历判断当前bean是否是一个Aspect注解类,若是则调用advisorFactory.getAdvisors获取所有通知器列表,其中会为每个方法调用getAdvisor方法,这个方法会获取AspectJ表达式切点(也就是获取方法上的相关注解如@Before@After等并创建一个AspectJExpressionPointcut对象),并且创建Advisor实现类(这其中会先根据注解类型创建相应的通知Advice实现类)。

创建代理对象

当Bean实现了接口时,Spring会基于JDK动态代理为目标Bean创建代理对象,若未实现任何接口,Spring则会通过CGLIB创建代理,而当proxy-target-class属性设为true时,则会强制Spring通过CGLIB的方式创建代理对象,即使目标Bean实现了接口。

AopProxy

为目标Bean创建代理对象前,需要先创建AopProxy对象,然后再调用该对象的getProxy方法创建实际的代理类:

1
2
3
4
5
public interface AopProxy {
Object getProxy();

Object getProxy(@Nullable ClassLoader classLoader);
}

在Spring中,有两个类实现了AopProxy,一个是CglibAopProxy,另一个是JdkDynamicAopProxy。在postProcessAfterInitialization的第三步Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));会根据bean是否实现接口以及一些其它配置来决定使用AopProxy的哪一个实现类为目标bean创建代理对象。

拦截器链的执行过程

在上面两个步骤中,Spring AOP已经为目标bean筛选出合适的通知器,创建好了代理对象,接下来就是要执行通知逻辑了。通知可能在目标方法前执行,也可能在目标方法后执行,当目标方法被多个通知匹配到时,Spring通过引入拦截器链来保证每个通知的正常执行。

JDK动态代理逻辑分析

对于JDK动态代理,代理逻辑封装在InvocationHandler接口实现类的invoke中,而JdkDynamicAopProxy实现了InvocationHandler接口:

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
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;
Object target = null;

try {
// ...
Object retVal;

if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);

// 获取适合当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

if (chain.isEmpty()) { // 如果拦截器链为空,则直接执行目标方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); // 通过反射执行目标方法
} else {
// 创建一个方法调用器,并将拦截器链传入其中
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行拦截器链
retVal = invocation.proceed();
}

// ...
return retVal;
} finally {
// ...
}
}
}

该方法的主要流程如下:

  1. 获取适合当前方法的拦截器(将advisor中的advice转成相应的拦截器)
  2. 如果拦截器链为空,则直接通过反射执行目标方法
  3. 否则,创建方法调用器ReflectiveMethodInvocation对象,将拦截器链传入其中
  4. 调用ReflectiveMethodInvocation对象的proceed()方法启动拦截器链
  5. 处理返回值,并返回该值

其中,启动拦截器是核心步骤,ReflectiveMethodInvocationproceed方法用于启动拦截器链,这里直接引用一副图很好的解释了拦截器链的执行过程:

由上图可以看出,方法调用器每次调用下一个拦截器的invoke方法时,都会将自己作为参数传给该方法,并且通过方法调用器不断调用下一个拦截器,直到拦截器链中的最后一个拦截器执行完后,通过反射的方式执行目标方法,然后再返回到后置拦截器的方法中执行后置拦截器的一些逻辑。