Spring AOP 源码深度解析:从代理创建到通知执行的完整链路
在上一篇文章中,我们掌握了 Spring AOP 的基本用法和核心概念。但"知其然"之后,更要"知其所以然"。
今天,我们将深入 Spring Framework 源码(以 Spring 6.2.x 为例),一步步拆解 Spring AOP 的实现原理,揭开动态代理与通知链的神秘面纱。
一、入口:@EnableAspectJAutoProxy 做了什么?
当你在配置类上加上:
kotlin
@EnableAspectJAutoProxy
public class AopConfig {}
这个注解的定义如下(简化):
less
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(AspectJAutoProxyRegistrar.class) // ← 关键!
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
▶ 核心动作:注册一个 BeanDefinition 后处理器
AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,它的作用是在容器启动时 向 Spring 容器注册一个特殊的 BeanPostProcessor:
typescript
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(...) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
}
继续跟进,最终会注册一个名为 internalAutoProxyCreator 的 Bean,其实现类是:
AnnotationAwareAspectJAutoProxyCreator
这是整个 Spring AOP 的核心引擎,它继承自:
markdown
AnnotationAwareAspectJAutoProxyCreator
└── AspectJAwareAdvisorAutoProxyCreator
└── AbstractAdvisorAutoProxyCreator
└── AbstractAutoProxyCreator
└── SmartInstantiationAwareBeanPostProcessor
也就是说,它是一个 BeanPostProcessor ------ 这意味着它能在每个 Bean 初始化前后进行干预!
二、代理对象何时创建?
AbstractAutoProxyCreator 重写了 postProcessAfterInitialization 方法:
typescript
@Override
public Object postProcessAfterInitialization(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:决定是否需要代理
这个方法做了三件事:
- 跳过不需要代理的 Bean(如 Advisor、Advice 本身)
- 查找所有匹配当前 Bean 的 Advisor(通知器)
- 如果有匹配的 Advisor,则创建代理对象
typescript
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 1. 获取所有适用的 Advisor(包含 Pointcut + Advice)
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 2. 创建代理
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return bean;
}
✅ 关键点:只有存在匹配的切面(Advisor),才会为该 Bean 创建代理!
三、如何查找匹配的 Advisor?------ 切面的"匹配逻辑"
getAdvicesAndAdvisorsForBean() 最终会调用:
kotlin
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
this.extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
try {
eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
} catch (BeanCreationException ex) {
throw new AopConfigException("Advisor sorting failed with unexpected bean creation, probably due to custom use of the Ordered interface. Consider using the @Order annotation instead.", ex);
}
}
return eligibleAdvisors;
}
其中,findAdvisorsThatCanApply 会遍历每个 Advisor,并调用其内部的 Pointcut 的 getClassFilter().matches() 和 getMethodMatcher().matches()。
例如,你写的:
java
@Pointcut("execution(public * org.example.spring.aop.service..*.*(..))")
会被解析为一个 AspectJExpressionPointcut,其 matches() 方法会使用 AspectJ 表达式引擎判断目标方法是否匹配。
🔍 注意:Spring AOP 虽然使用 AspectJ 的注解和表达式语法,但匹配逻辑由 Spring 自己实现,并未依赖完整的 AspectJ 编译器。
四、代理对象如何创建?------ JDK Proxy vs CGLIB
createProxy() 方法内部会根据配置和目标类特性选择代理方式:
arduino
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 满足任一条件时,优先考虑使用 CGLIB 代理:
// - config.setOptimize(true):启用优化(已废弃,但保留兼容)
// - config.setProxyTargetClass(true):强制使用 CGLIB(如 @EnableAspectJAutoProxy(proxyTargetClass = true))
// - 没有用户显式指定接口(即目标类未实现任何业务接口)
if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) {
Class<?> targetClass = config.getTargetClass();
// 校验:必须能确定目标类型(要么有目标类,要么有接口)
if (targetClass == null && config.getProxiedInterfaces().length == 0) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 若目标类为 null、是接口、已是 JDK 代理类、或是 Lambda 表达式生成的类,
// 则仍使用 JDK 动态代理(CGLIB 无法代理接口或特殊类)
if (targetClass == null ||
targetClass.isInterface() ||
Proxy.isProxyClass(targetClass) ||
ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用 CGLIB 代理(通过 Objenesis 优化实例化性能)
return new ObjenesisCglibAopProxy(config);
}
else {
// 明确指定了接口且未强制 CGLIB → 使用 JDK 动态代理
return new JdkDynamicAopProxy(config);
}
}
- 若目标类实现了接口 → 默认用 JDK Proxy
- 若未实现接口 或 设置了
proxyTargetClass=true→ 用 CGLIB
✅ Spring 默认优先使用 JDK 动态代理(基于接口),只有在必要时才回退到 CGLIB。
五、方法调用时:通知如何执行?------ 责任链模式
假设我们获取的是一个 JDK 代理对象 ,其 InvocationHandler 是 JdkDynamicAopProxy。
当调用 orderService.placeOrder(...) 时,实际执行的是:
typescript
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 构建拦截器链(Interceptor Chain)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 无通知,直接调用目标方法
return method.invoke(target, args);
} else {
// 2. 执行责任链
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
return invocation.proceed(); // ← 递归执行通知链
}
}
▶ 拦截器链(Interceptor Chain)的组成
每个 @Before、@AfterReturning 等注解,最终都会被包装成一个 MethodInterceptor:
| 注解 | 对应的 Interceptor |
|---|---|
@Before |
MethodBeforeAdviceInterceptor |
@AfterReturning |
AfterReturningAdviceInterceptor |
@Around |
直接实现 MethodInterceptor |
@AfterThrowing |
ThrowsAdviceInterceptor |
这些 Interceptor 按照 通知类型 + 切面优先级 排序,形成一条链。
▶ proceed() 的递归执行机制
ReflectiveMethodInvocation.proceed() 是典型的责任链递归实现:
java
public Object proceed() throws Throwable {
if (currentInterceptorIndex == interceptors.length - 1) {
// 所有通知执行完毕,调用目标方法
return method.invoke(target, arguments);
}
// 获取下一个通知
Object interceptor = interceptors[++currentInterceptorIndex];
if (interceptor instanceof MethodInterceptor) {
return ((MethodInterceptor) interceptor).invoke(this); // ← 递归
}
// ...
}
以 @Before + @Around + @AfterReturning 为例,执行顺序如下:
scss
Around.before()
→ Before通知
→ 目标方法
→ AfterReturning通知
→ Around.after()
✅ 环绕通知(@Around)拥有最高控制权 :它可以决定是否调用
proceed(),甚至修改参数或返回值。
六、为什么"自调用"不触发 AOP?
考虑以下代码:
typescript
@Service
public class OrderService {
public void methodA() {
this.methodB(); // ← 自调用!
}
@Transactional
public void methodB() { ... }
}
▶ 根本原因:绕过了代理对象
- Spring 容器中保存的是 代理对象(Proxy)
- 但在
methodA()内部,this指向的是 原始的 OrderService 实例,而非代理 - 因此
this.methodB()直接调用原始方法,不会进入JdkDynamicAopProxy.invoke()
▶ 解决方案
-
注入自身(推荐) :
typescript@Autowired private OrderService self; // 注入的是代理对象 public void methodA() { self.methodB(); // 通过代理调用 } -
使用
AopContext.currentProxy()(需开启暴露):typescript@EnableAspectJAutoProxy(exposeProxy = true) public class AopConfig {} public void methodA() { ((OrderService) AopContext.currentProxy()).methodB(); }
⚠️ 注意:第二种方式耦合了 AOP 框架,一般不推荐。
七、总结 Spring AOP 执行流程
scss
[Spring 容器启动]
↓
@EnableAspectJAutoProxy → 注册 AnnotationAwareAspectJAutoProxyCreator
↓
Bean 初始化完成 → postProcessAfterInitialization()
↓
wrapIfNecessary() → 查找匹配的 Advisor
↓
存在匹配切面? → 是 → createProxy() → 返回代理对象
↓ 否
返回原始 Bean
↓
调用代理方法 → JdkDynamicAopProxy.invoke() / CglibAopProxy.intercept()
↓
构建 Interceptor 链 → ReflectiveMethodInvocation.proceed()
↓
依次执行 @Before → @Around → 目标方法 → @AfterReturning/@AfterThrowing → @After
八、结语:AOP 的本质是"代理 + 责任链"
Spring AOP 并非魔法,而是巧妙结合了:
- BeanPostProcessor:在 Bean 初始化后动态包装
- 动态代理(JDK/CGLIB) :拦截方法调用
- 责任链模式:组织多个通知的执行顺序
- AspectJ 表达式:提供灵活的切入点匹配能力
理解了这套机制,你不仅能用好 AOP,还能在排查"为什么 AOP 不生效"时直击根源。
📌 关注我 ,每天5分钟,带你从 Java 小白变身编程高手!
👉 点赞 + 关注,让更多小伙伴一起进步!