📌 阅读前提示 :上篇我们把 AOP 的术语和注解讲透了。从本篇起连续三篇钻源码。本篇回答一个最基础的问题:
@EnableAspectJAutoProxy这个注解,在容器启动时到底「偷偷」干了什么?答案只有一句话------往容器里注册了一个BeanPostProcessor。但这句话背后的调用链,值得你跟一遍。
一、引子:一个被低估的注解
很多人的认知停留在「加了 @EnableAspectJAutoProxy 注解,AOP 就生效了」。但面试一旦被追问「它注册了哪个类?这个类在哪一步介入 Bean 生命周期?」,就卡壳了。
本篇带你把这条链走通:
@EnableAspectJAutoProxy
→ @Import(AspectJAutoProxyRegistrar.class)
→ registerBeanDefinitions()
→ 注册 internalAutoProxyCreator
= AnnotationAwareAspectJAutoProxyCreator (一个 BeanPostProcessor)
记住结论:@EnableAspectJAutoProxy 本身不创建代理,它只是把一个「能创建代理的 BPP」塞进容器。
二、源码追踪:从注解到注册
2.1 注解的 @Import
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) // ← 关键:导入一个 Registrar
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false; // 是否强制 CGLIB
boolean exposeProxy() default false; // 是否暴露代理到 AopContext
}
@Import 在 IoC 阶段(第 5 篇第 5 步 invokeBeanFactoryPostProcessors)被 ConfigurationClassPostProcessor 解析,触发 AspectJAutoProxyRegistrar.registerBeanDefinitions()。
2.2 AspectJAutoProxyRegistrar 注册核心类
java
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// ① 注册自动代理创建器(如果容器中还没有)
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// ② 读取 @EnableAspectJAutoProxy 的两个属性,回写到 BD
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); // 强制 CGLIB
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); // 暴露代理
}
}
}
}
2.3 注册的真实类名
java
// AopConfigUtils.java
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(
AnnotationAwareAspectJAutoProxyCreator.class, registry, source); // ← 真正注册的类
}
最终以 Bean 名 org.springframework.aop.config.internalAutoProxyCreator 注册了一个 AnnotationAwareAspectJAutoProxyCreator 的 BeanDefinition。

📌 结论 :
internalAutoProxyCreator就是AnnotationAwareAspectJAutoProxyCreator,它实现了SmartInstantiationAwareBeanPostProcessor(继承链最终是BeanPostProcessor)。
三、这个 BPP 在生命周期的哪一步介入
回顾第 7 篇生命周期:普通 BeanPostProcessor.postProcessAfterInitialization 在 initializeBean 末尾执行。AnnotationAwareAspectJAutoProxyCreator 正是利用这一步「动手脚」。
| 阶段 | 方法 | 作用 |
|---|---|---|
| 实例化后、属性填充前 | getEarlyBeanReference |
处理循环依赖时的早期代理(见第 9 篇) |
| 初始化后 | postProcessAfterInitialization |
创建 AOP 代理(核心,第 13 篇详述) |
java
// AbstractAutoProxyCreator.java(父类)
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey); // ← 必要时包成代理
}
}
return bean;
}
💡 重点 :
wrapIfNecessary是「是否代理」的总开关。如果你的 Bean 不匹配任何切面 Pointcut,这里原样返回,不做任何包装------这也是为什么不是所有 Bean 都被代理。
四、proxyTargetClass / exposeProxy 最终落到哪
这两个属性并非直接存着,而是被 AopConfigUtils 写进 internalAutoProxyCreator 这个 BD 的 propertyValues:
java
// forceAutoProxyCreatorToUseClassProxying
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); // 强制 CGLIB
}
// forceAutoProxyCreatorToExposeProxy
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); // 暴露代理
后续该 BPP 实例化后,proxyTargetClass / exposeProxy 作为它的字段,在第 14 篇「JDK 还是 CGLIB」的选择逻辑中被读取。
五、Spring Boot 为什么「不用写」这个注解
Spring Boot 的 AopAutoConfiguration 帮你自动 @Import 了等效配置:
java
@Configuration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
@EnableAspectJAutoProxy(proxyTargetClass = true) // ← Boot 默认 proxyTargetClass=true
public class AopAutoConfiguration {
// 注意:Boot 默认 exposeProxy=false,需要自调用代理时仍需手动开
}
⚠️ 注意 :
spring.aop.proxy-target-class默认true,即 Boot 项目默认走 CGLIB 子类代理(即使你的类实现了接口)。这与「纯 Spring 默认优先 JDK 动态代理」不同,是面试常挖的坑。
六、常见误区
| 误区 | 正解 |
|---|---|
@EnableAspectJAutoProxy 直接创建代理 |
不,它只注册 AnnotationAwareAspectJAutoProxyCreator 这个 BPP |
| Boot 项目不用配就走 JDK 动态代理 | Boot 默认 proxyTargetClass=true,默认 CGLIB |
注册的是 @Aspect 类本身 |
注册的是「自动代理创建器」,与你的切面类无关 |
exposeProxy 默认开启 |
默认 false,自调用代理失效需手动开 |
🧪 面试题自测
@EnableAspectJAutoProxy通过什么机制注册类?注册的是哪个类?Bean 名是什么?AnnotationAwareAspectJAutoProxyCreator在 Bean 生命周期的哪一步创建代理?proxyTargetClass=true和exposeProxy=true最终被写到哪里?- Spring Boot 下 AOP 默认用 JDK 还是 CGLIB?为什么?
- 如果容器里已存在
internalAutoProxyCreator,再@Import会怎样?(提示:registerOrEscalateApcAsRequired的优先级升级逻辑)
🔧 Debug 小技巧
在 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary 打断点,观察 beanName = "org.springframework.aop.config.internalAutoProxyCreator" 的 BeanDefinition 是如何生成的;再在 AbstractAutoProxyCreator.postProcessAfterInitialization 断点,看它如何对所有 Bean「过一遍」wrapIfNecessary。
下一篇预告
第 13 篇:代理到底在「什么时机」创建?深入 wrapIfNecessary → getAdvicesAndAdvisorsForBean → createProxy,看清 shouldSkip 排除逻辑,以及为何代理创建发生在初始化之后而非之前。
如果这篇对你有帮助,欢迎 点赞 · 收藏 · 关注 三连支持。
Spring 源码系列共 30 篇,由浅入深持续更新中。有疑问或想深挖的源码点,评论区告诉我,下篇见。