理解了 AOP 的概念与使用方式后,深入其内部实现有助于排查问题、定制扩展,也能更自信地运用这项能力。Spring AOP 的底层建立在 动态代理 与 拦截器链 两大机制之上,整体流程可分为“代理创建”和“代理调用”两个阶段。本节以最常用的 @EnableAspectJAutoProxy 开启方式为主线,梳理核心源码脉络。
26.3.1 开启 AOP 的入口
在配置类上标注 @EnableAspectJAutoProxy,会通过 @Import 引入 AspectJAutoProxyRegistrar,后者向容器注册一个关键的 BeanPostProcessor:
org.springframework.aop.config.internalAutoProxyCreator
→ AnnotationAwareAspectJAutoProxyCreator
这个类继承体系如下图所示(简化版):
AbstractAutoProxyCreator
└─ AbstractAdvisorAutoProxyCreator
└─ AspectJAwareAdvisorAutoProxyCreator
└─ AnnotationAwareAspectJAutoProxyCreator
核心逻辑聚集在 AbstractAutoProxyCreator,它实现了 BeanPostProcessor,专门在 Bean 初始化完成后“拦截”并决定是否为其创建代理。
26.3.2 代理创建流程
1. 入口:postProcessAfterInitialization
AbstractAutoProxyCreator 覆写了 postProcessAfterInitialization,每个 Bean 初始化完毕都会进入此方法,核心调用链为:
// AbstractAutoProxyCreator
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary 就是决定是否创建的关卡。
2. wrapIfNecessary:获取匹配的 Advisors
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 跳过基础设施类,如 Advisor、Advice 等本身
if (isInfrastructureClass(bean.getClass())) {
return bean;
}
// 获取所有可用的 Advisor(包含切面中定义的 Advice + Pointcut)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,
new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return bean;
}
关键步骤是 getAdvicesAndAdvisorsForBean,它会:
- 从容器中拿到所有 Advisor(包括切面解析出的 Advisor,例如每个
@Before、@After都被封装成InstantiationModelAwarePointcutAdvisor)。 - 遍历这些 Advisor,使用 Pointcut 的
ClassFilter和方法级别的MethodMatcher判断是否与当前 Bean 匹配。 - 返回匹配的 Advisor 数组。
3. createProxy:生成代理对象
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory factory = new ProxyFactory();
factory.setTargetSource(targetSource);
// 添加匹配的 Advisors
for (Object specificInterceptor : specificInterceptors) {
factory.addAdvisor(advisor);
}
// 判断使用 JDK 动态代理还是 CGLIB
// 如果目标类实现了接口,且未强制使用 CGLIB,则选用 JDK 代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
factory.setProxyTargetClass(false); // JDK 代理
} else {
factory.setProxyTargetClass(true); // CGLIB 代理
}
return factory.getProxy(classLoader);
}
- JdkDynamicAopProxy:实现
InvocationHandler,通过java.lang.reflect.Proxy创建代理,要求目标类必须实现至少一个接口。 - CglibAopProxy:通过 CGLIB 生成目标类的子类作为代理,可代理没有实现接口的类。Spring Boot 从 2.x 开始默认代理策略已倾向 CGLIB(通过
spring.aop.proxy-target-class=true)。
代理类在内存中生成,并替换原 Bean 存放于容器中。此后所有对该 Bean 的调用都会经过代理。
26.3.3 代理调用流程
以 JdkDynamicAopProxy.invoke 为例,代理对象接收到方法调用时,进入此方法。
1. 获取拦截器链
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取适用于该方法的拦截器链(MethodInterceptor 列表)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果没有拦截器,直接反射调用目标方法
if (chain.isEmpty()) {
return AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
// 否则创建一个 ReflectiveMethodInvocation,串联调用链
MethodInvocation invocation = new ReflectiveMethodInvocation(
proxy, target, method, args, targetClass, chain);
return invocation.proceed();
}
Advisor 与 Interceptor 的转换:配置的切面最终会被映射成 MethodInterceptor 对象。比如 @Before 会被包装成 MethodBeforeAdviceInterceptor,@AfterReturning 包装成 AfterReturningAdviceInterceptor,而 @Around 本身就实现了 MethodInterceptor。它们共同存放在链中。
2. ReflectiveMethodInvocation.proceed() 递归执行
public Object proceed() throws Throwable {
// currentInterceptorIndex 从 -1 开始
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 所有拦截器执行完毕,调用目标方法
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 如果是 InterceptorAndDynamicMethodMatcher,需动态匹配
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 省略动态匹配逻辑
} else {
// 普通 MethodInterceptor,直接调用其 invoke
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这是一个典型的责任链模式:每个拦截器在内部调用 invocation.proceed() 来推动链继续前进,顺序等同于配置的顺序。以 @Around → @Before → 目标方法 → @AfterReturning → @After 为例,调用栈大致如下:
@Around拦截器执行前半段逻辑,然后调用proceed()。@Before拦截器执行通知逻辑,然后调用proceed()。- 链尾调用目标方法本身。
- 目标方法返回后,栈回退:
@Around的后半段逻辑执行,@AfterReturning、@After按顺序执行。
最后返回结果到最外层调用者。
26.3.4 核心类关系小结
| 类 / 接口 | 职责 |
| --- | --- |
| AnnotationAwareAspectJAutoProxyCreator | 注册到容器的 BeanPostProcessor,触发代理创建。 |
| AbstractAutoProxyCreator | 模板方法,提供 wrapIfNecessary 和 createProxy。 |
| Advisor | 持有 Advice 和 Pointcut,提供匹配能力。 |
| JdkDynamicAopProxy | JDK 代理实现,invoke 内组装拦截器链并执行。 |
| CglibAopProxy | CGLIB 代理实现,原理类似。 |
| ReflectiveMethodInvocation | 封装调用过程,proceed() 按序执行拦截器链。 |
26.3.5 调试与排错启发
掌握上述流程后,遇到 AOP 不生效的问题,可以从以下方向排查:
- Bean 是否被容器管理:代理创建的前提是 Bean 经由 Spring 容器生命周期(
postProcessAfterInitialization被触达)。 - 内部调用导致代理失效:在同一个类中方法 A 调用方法 B,会直接使用
this引用,绕过代理,切面不生效。解决方式:注入自身代理,或使用AopContext.currentProxy()。 - 切点表达式是否正确:可开启
spring.aop.auto=false并手动打印getAdvicesAndAdvisorsForBean的返回值验证。 - 方法访问修饰符:Spring AOP 只能拦截 public 方法,CGLIB 代理也受此限制。
理解 AOP 的源码流程,不是要去记忆每一行实现,而是让你对“为什么这样写通知会执行在那个位置”有了清晰的认知,从而更自信地使用和诊断这个强大的工具。