前言
本文是看了田小波博主的Spring AOP源码分析系列后自己总结整理的笔记,内容会更偏向于流程上的总结,具体源码细节并未深入研究,并且关于AOP的相关术语这里也不会再说明。
大致流程
本文将会从AOP的入口开始分析,主要涉及以下四个流程:
- 入口分析
- 筛选合适的通知器
- 创建代理对象
- 拦截器链的执行过程
入口分析
Spring是通过后置处理器BeanPostProcessor
接口在init-method
的前后通过切点对bean类中的方法进行匹配后织入的,这个接口是Spring提供的一个扩展接口,通过实现该接口,用户可在Bean初始化前后做一些自定义的操作:
1 | protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { |
Spring AOP抽象代理创建器AbstractAutoProxyCreator
实现了BeanPostProcessor
接口,并在Bean初始化后置处理过程中向Bean织入通知:
1 | public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport |
可以看出,postProcessAfterInitialization
主要过程分为四步:
- 若Bean是AOP基础设施类型(Pointcut、Advice、Advisor 等接口的实现类),则直接返回
- 为目标Bean查找匹配的通知器(通知器持有通知)
- 如果找到了匹配的通知器,则为Bean生成代理对象,并返回该对象
- 否则,返回原始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
23protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, 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;
}
该过程首先会查询出所有的通知器,然后再通过ClassFilter
和MethodMatcher
对目标类和方法进行匹配,筛选出可应用到当前bean的通知器。下面分析查询出所有的通知器的过程。
查找所有通知器
这个方法在子类AnnotationAwareAspectJAutoProxyCreator
中被覆写过,增加了对@Aspect
注解的解析:
1 |
|
这两行代码分别做了两件事:
- 第一步从容器中获取所有类型为
Advisor
的bean - 第二步获取容器中所有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
5public 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
45final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
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 {
// ...
}
}
}
该方法的主要流程如下:
- 获取适合当前方法的拦截器(将advisor中的advice转成相应的拦截器)
- 如果拦截器链为空,则直接通过反射执行目标方法
- 否则,创建方法调用器
ReflectiveMethodInvocation
对象,将拦截器链传入其中 - 调用
ReflectiveMethodInvocation
对象的proceed()
方法启动拦截器链 - 处理返回值,并返回该值
其中,启动拦截器是核心步骤,ReflectiveMethodInvocation
的proceed
方法用于启动拦截器链,这里直接引用一副图很好的解释了拦截器链的执行过程:
由上图可以看出,方法调用器每次调用下一个拦截器的invoke
方法时,都会将自己作为参数传给该方法,并且通过方法调用器不断调用下一个拦截器,直到拦截器链中的最后一个拦截器执行完后,通过反射的方式执行目标方法,然后再返回到后置拦截器的方法中执行后置拦截器的一些逻辑。