spring--aop 原理分析

如何启用AOP

引入依赖后,类路径存在 Aspect.class、Advice.class、AnnotatedElement.class 因此自动化配置类AopAutoConfiguration生效。

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {

}

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {

}

}

完整的切面定义

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
@Aspect
@Component
public class LogAspect {

@Pointcut("execution(public * com.mrglint.springbootdemo.service..*.*(..))")
private void pointCut(){

}

/**
* 切面作用于 com.mrglint.springbootdemo 下的子包以及子包下的子包,任意类的任意方法
* @param joinPoint
*/
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("doBefore run...");
}

@After("pointCut()")
public void doAfter(JoinPoint joinpoint) {
System.out.println("doAfter run...");
}

@AfterReturning(value = "pointCut()", returning = "res")
public void doAfterReturning(JoinPoint joinPoint, Object res) {
System.out.println("doAfterReturning run, result: " + res);
}

@AfterThrowing(value = "pointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("doAfterThrowing run, exception: " + e);
}

@Around("pointCut()")
public Object doArround(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("doArround run on before...");
Object res = null;
try {
res = proceedingJoinPoint.proceed();
System.out.println("doArround run on after");
} catch (Throwable throwable) {
System.out.println("doArround run on throw exception: " + throwable);
throwable.printStackTrace();
}
return res;
}

}

暴露代理类到ThreadLocal

可以通过配置 exposeProxy = true来暴露代理对象到ThreadLocal中,之后在被代理类对象内部可以使用 AopContext.currentProxy() 来获取代理类对象

1
2
// 默认为false
@EnableAspectJAutoProxy(exposeProxy = true)

创建代理流程

AnnotationAwareAspectJAutoProxyCreator结构

由@EnableAspectJAutoProxy导入的AspectJAutoProxyRegistrar注册到beanfactory中,作为一个BeanPostProcessor存在

企业微信截图_e5c06bc5-9a6f-41de-b597-6c19ae673c88

"

创建代理时序图

企业微信截图_1505c8e6-56c2-40b5-82de-b733e38bf057

"

调用代理

在了解调用代理的逻辑之前,我们来回顾创建代理对象的方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// JdkDynamicAopProxy.getProxy
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// JDK动态代理,JdkDynamicAopProxy自身作为 InvocationHandler对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

代理类执行代码

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
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 执行被代理方法
return invokeJoinpoint();
}

// 获取第一个切面逻辑拦截器。一开始为 (-1 + 1) = 0,interceptorsAndDynamicMethodMatchers 中的第一个
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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 {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

执行时序

企业微信截图_5ebfb165-5267-4c8c-ae00-ca47d11ea54d

"

参考资料

Spring AOP原理分析