0%

SpringAop浅析(二)

SpringAop浅析(二)

介绍

​ 接两年前的旧文SpringAop浅析,时隔两年再一次对SpringAop相关源码进行分析,只能说之前阅读的不够透彻,理解的不扎实,再加上工作上常年忙于业务的处理,现在已经少有看源码的时间,不过最近不知道是因为什么打了鸡血,还是想再沉淀沉淀。

上篇回顾

​ 前面说到SpringAop的大致创建时机、创建流程和基本的调用流程。SpringAop是采用动态代理的方式实现,通过@EnableAspectJAutoProxy的方式开启,开启的原理为添加AnnotationAwareAspectJAutoProxyCreator后置处理器到BeanDefinitionMap中;在Bean对象实例化之前可以通过用户自定义的方式进行提前生成代理对象。或者是在Bean对象初始化之后,通过上述后置处理器的postProcessAfterInitialization方法,将Bean对象转为代理对象。

本篇想说明一个问题:被SpringAop代理之后的对象是什么对象?在调用被代理方法时,它具体的执行过程?

解析

​ 直接debug可以得知,被SpringAop代理之后的对象是CglibAopProxy#DynamicAdvisedInterceptor类的实现。(使用cglib代理的前提)

这个类是CglibAopProxy的内部类,它实现了MethodInterceptor接口,学过cglib动态代理的知道MethodInterceptor是它的代理类的增强,所以DynamicAdvisedInterceptor这个类就是为了aop来做增强的实现。

1
2
3
4
5
6
7
8
9
10
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

private final AdvisedSupport advised;

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// ...代码省略
}
}

它定义了AdvisedSupport增强支持类。

1
2
3
4
5
6
7
8
9
public class AdvisedSupport extends ProxyConfig implements Advised {
// 这个类记录了被代理对象、被代理方法等等一系列的动态代理需要的参数等
// 这个是一个重要的参数,它记录了这个被代理对象需要被执行增强的列表
// 比如说你定义了一个方法,需要在这个方法上做
// 1.打印访问时长的增强A,
// 2.记录方法执行前后参数、返回值的增强B
// 都会被记录在这个列表里
private List<Advisor> advisors = new ArrayList<>();
}

所以到这里可以知道,在项目中我们通过SpringAop得到的代理对象的增强是DynamicAdvisedInterceptor。故在执行被代理方法时,会直接进入到它的拦截方法中。

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
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
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);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 创建CglibMethodInvocation类,并执行processd()方法
// CglibMethodInvocation类实际上是一个调用链对象,也就是说这里将目标类、代理对象、代理方法、调用参数、以及最关键的增强列表<chain>
// 记录到这个对象中,还包含了当前索引下标等等信息。也就是调用它的process()方法之后,它就会遍历这个增强列表,执行每一个增强。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

进入到process()方法。

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
public Object proceed() throws Throwable {
// 到达链尾时进入被代理对象的目标方法中,至此递归结束
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 遍历下标,取出对应的增强
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 根据对应的信息进行匹配器的匹配,若匹配成功则执行增强的拦截方法
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 匹配失败,则进入到下一个链节点
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

​ 以上便是springAop的大致过程,这里还要提到一个问题,如果对aop的这个执行过程进行过debug的会发现,假设我只设置了一个aop的注解拦截,对于上面提到的增强拦截链的List<Advisor> advisors实际上会有两个对象,如果设置了两个aop的注解拦截,那么这个列表中会有3个对象。

​ 通过观察不难发现,是springAop在创建实例对象,如果需要被aop代理时,它会将ExposeInvocationInterceptor类,固定放置在这个列表的下标为0的位置。

AbstractAdvisorAutoProxyCreator它实现了spring后置处理器接口,就是它在创建具体的代理对象时,将ExposeInvocationInterceptor放置在增强链的头部位置。

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
// 找出满足这个将要创建的bean对象的增强,做法是从容器中首先找出所有Advisor.class的实现类
// 再根据一定的逻辑进行匹配,这里在获取之后会进行缓存,下次在获取Advisor.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;
}


public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// 对获取到的增强列表进行遍历,这里来了一个二次核查,如果存在aop的增强,则在列表下标为0的位置,添加
// ExposeInvocationInterceptor类。
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}

那么,这个被加到增强列表头部的增强,有什么特殊的作用?

直接看它的拦截方法,他的拦截方法也比较简单。

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
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 这里接收到的参数MethodInvocation实际上是aop代理类(链对象)
// 重新来捋一下这个过程,在执行到对应aop的代理类之时:
// 1.进入到了CglibAopProxy#intercept拦截方法
// 2.用匹配的增强列表、代理类、被代理目标类(方法)的信息、具体方法、参数等创建CglibMethodInvocation
// 注意这个类实现了MethodInvocation,然后调用了它的process()方法。
// 3.这个process()拦截方法的实现上,主要是要遍历增强列表,进行增强的播放,当进入到首个增强时
// 进入到ExposeInvocationInterceptor#invoke()方法中,来执行以下这段代码。
// 4.这段代码的作用是将这个aop代理类对象放置到线程上下文中,以便于后续的增强获取。


// 从线程上下文中获取旧methodInvocation对象
MethodInvocation oldInvocation = invocation.get();
// 将线程上下文替换为这个aop代理类对象,在后面的遍历增强类的过程中,
// 通过线程上下文来获取这个aop代理类对象。
invocation.set(mi);
try {
return mi.proceed();
}
finally {
// 还原现场
invocation.set(oldInvocation);
}
}

总结

springAop在初始化对象之后的代理类是CglibAopProxy#DynamicAdvisedInterceptor的实现(使用cglib代理的情况下),当执行到这个代理类进入到了CglibAopProxy#intercept拦截方法,这个方法中用匹配的增强列表、代理类、被代理目标类(方法)的信息、具体方法、参数等创建CglibMethodInvocation,注意这个类实现了MethodInvocation,然后调用了它的process()方法。这个process()拦截方法的实现上,主要是要遍历增强列表,进行增强的播放,当进入到首个增强时,进入到ExposeInvocationInterceptor#invoke()方法中,将这个aop代理类对象(CglibAopProxy#DynamicAdvisedInterceptor)放置到线程上下文中,以便于后续的增强获取。

-------------本文结束感谢您的阅读-------------