一、先搞懂核心前提:Spring AOP 底层基础
1. AOP 核心概念
| 概念 | 源码对应 | 核心含义 |
|---|---|---|
| 切面 Aspect | @Aspect 标注的类 |
切点 + 通知的集合,定义横向逻辑的类 |
| 切点 Pointcut | @Pointcut 标注的方法 |
定义哪些类/方法需要被拦截增强 |
| 通知 Advice | @Before/@Around/@After 等 |
拦截到方法后,要执行的横向逻辑 |
| 通知器 Advisor | Advisor 接口 |
Spring AOP 中切点(Pointcut)与通知(Advice)的封装单元,是 Spring 判定 Bean 是否需要代理、如何代理的核心依据,是 AOP 执行的最小逻辑单元 |
| 动态代理 | JdkDynamicAopProxy / CglibAopProxy |
AOP 的底层实现,生成代理对象替代原生 Bean |
2. 两种动态代理的核心区别
Spring AOP 仅支持两种动态代理,源码中会自动选择:
| 特性 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|
| 底层实现 | 基于接口,生成实现类的代理 | 基于继承,生成目标类的子类代理 |
| 代理对象生成 | 快 | 慢 |
| 方法执行效率 | 低(反射调用) | 高(字节码生成,无反射) |
| Spring 默认选择 | 目标类实现了接口时优先使用 | 目标类无接口时使用 |
二、AOP 开启的入口:@EnableAspectJAutoProxy
我们使用 Spring AOP 时,只需要加一个注解:
java
@Configuration
@EnableAspectJAutoProxy // 开启AOP
@ComponentScan("com.example")
public class SpringConfig {
}
这个注解,就是 AOP 所有逻辑的起点。
1. 注解源码拆解
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) // 核心:导入了注册器
public @interface EnableAspectJAutoProxy {
// 强制使用CGLIB代理,默认false
boolean proxyTargetClass() default false;
// 暴露代理对象到ThreadLocal,解决内部调用AOP失效问题,默认false
boolean exposeProxy() default false;
}
2. 核心:AspectJAutoProxyRegistrar 做了什么?
这个注册器的核心作用,就是向 Spring 容器中注册了一个核心 BeanPostProcessor:AnnotationAwareAspectJAutoProxyCreator
关键源码
java
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 核心:注册 AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 处理 proxyTargetClass、exposeProxy 配置
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
3. 灵魂核心:AnnotationAwareAspectJAutoProxyCreator
这个类,是 Spring AOP 的绝对核心,它的继承关系:
AnnotationAwareAspectJAutoProxyCreator
↓
AbstractAdvisorAutoProxyCreator
↓
AbstractAutoProxyCreator
↓
实现了 BeanPostProcessor 接口
为什么它是核心?
- 它是一个
BeanPostProcessor,会介入每一个 Bean 的生命周期 - 它负责:扫描解析所有
@Aspect切面,生成 Advisor - 它负责:判断 Bean 是否需要生成代理,生成代理对象
- 它就是我们第二篇 Bean 生命周期里,后置处理器中生成 AOP 代理的那个类
三、AOP 全流程第一阶段:容器启动时,切面解析与 Advisor 生成
Spring AOP 不是 Bean 创建时才解析切面,而是容器启动时,就提前扫描解析所有切面,生成 Advisor 通知器,对应我们第一篇的容器启动流程。
完整流程
- 容器启动,执行
refresh() - 执行
invokeBeanFactoryPostProcessors(),解析@EnableAspectJAutoProxy,注册AnnotationAwareAspectJAutoProxyCreator - 执行
registerBeanPostProcessors(),把AnnotationAwareAspectJAutoProxyCreator实例化,加入到 BeanPostProcessor 列表中 AnnotationAwareAspectJAutoProxyCreator提前扫描所有@Aspect注解的类,解析切点、通知,封装成一个个Advisor对象,缓存起来,供后续 Bean 创建时使用
核心源码:切面解析
java
// AnnotationAwareAspectJAutoProxyCreator 核心方法
protected List<Advisor> findCandidateAdvisors() {
// 1. 先拿到父类的Advisor
List<Advisor> advisors = super.findCandidateAdvisors();
// 2. 核心:扫描所有@Aspect注解的类,解析生成Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
关键细节
- 每个
@Before/@Around/@After等通知,都会被封装成一个独立的Advice(通知);Advice与对应的Pointcut(切点)组合,形成Advisor(通知器)。若多个通知关联同一个切点,会生成多个包含该切点的Advisor,执行顺序由@Order控制 - 每个
Advisor都包含:切点表达式(匹配哪些方法)+ 通知逻辑(要执行的代码) - 解析完成后,所有
Advisor会被缓存起来,后续每个 Bean 创建时,直接用这些Advisor匹配,判断是否需要生成代理
四、AOP 全流程第二阶段:Bean 创建时,代理对象生成
核心结论先记死:
AOP 代理对象,生成于 Bean 生命周期的「BeanPostProcessor 后置处理阶段」,也就是 initializeBean 方法的最后一步。
完整流程(对应 Bean 生命周期)
doGetBean → createBean → doCreateBean
↓
1. createBeanInstance:实例化原生Bean
↓
2. populateBean:填充属性,依赖注入
↓
3. initializeBean:初始化
• Aware接口执行
• BeanPostProcessor前置处理
• 初始化方法执行
• BeanPostProcessor后置处理【AOP代理生成就在这里!】
↓
4. 代理对象生成,替换原生Bean,放入单例池
1. 入口:后置处理方法
java
// AbstractAutoProxyCreator(父类)
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 核心:判断是否需要生成代理,需要则返回代理对象,否则返回原生Bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
return bean;
}
2. 核心判断:wrapIfNecessary(要不要生成代理)
java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 1. 提前判断:是否已经处理过,或者是切面类本身,不需要代理
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (this.advisedBeans.containsKey(cacheKey)) {
return this.advisedBeans.get(cacheKey);
}
// 2. 基础设施类(如 @Aspect 标注的切面类)或需跳过的 Bean,直接返回原生对象
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 3. 核心:匹配Advisor,判断当前Bean是否有匹配的切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 4. 有匹配的切面 → 生成代理对象
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// ↓↓↓ 生成代理对象 ↓↓↓
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象,替换原生Bean
return proxy;
}
// 5. 没有匹配的切面 → 返回原生Bean
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
3. 生成代理:createProxy
java
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 1. 封装代理配置
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 处理proxyTargetClass配置,决定用JDK还是CGLIB
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 2. 把Advisor加入代理工厂
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 3. 核心:生成代理对象
return proxyFactory.getProxy(getBeanClassLoader());
}
4. 代理选择逻辑:JDK 还是 CGLIB?
java
// DefaultAopProxyFactory
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 1. 强制CGLIB、或者目标类无接口 → 用CGLIB
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
// 2. 目标类实现了接口 → 用JDK动态代理
else {
return new JdkDynamicAopProxy(config);
}
}
五、循环依赖场景下,AOP 代理的特殊处理
前面我们介绍循环依赖时,提到了 getEarlyBeanReference 方法,这个方法就是循环依赖场景下,提前生成 AOP 代理的核心。
问题场景
A ↔ B 循环依赖,且 A 需要生成 AOP 代理:
- A 实例化后,暴露工厂到三级缓存
- B 创建时,需要注入 A,从三级缓存拿到 A 的工厂,执行
getEarlyBeanReference - 这里会提前生成 A 的 AOP 代理对象,注入到 B 中
- A 后续初始化完成后,不会再重复生成代理,保证单例
核心源码
java
// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 提前生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
关键细节
- 循环依赖场景下,代理对象会提前在
getEarlyBeanReference中生成(注入给依赖方),同时将原生 Bean 存入earlyProxyReferences缓存 - 后续执行
postProcessAfterInitialization时,会优先检查该缓存:若存在当前 Bean 的记录,则直接返回已生成的代理对象,避免重复代理 - 这就是为什么三级缓存要存工厂,而不是直接存 Bean 引用 ------ 为了支持循环依赖下的 AOP 代理提前生成
六、AOP 全流程第三阶段:运行时,通知链执行
代理对象生成后,当我们调用代理对象的方法时,就会触发切面通知的执行,Spring 通过责任链模式控制通知的执行顺序。
核心执行流程
- 调用代理对象的目标方法
- 进入代理对象的拦截器(JDK 的
InvocationHandler/ CGLIB 的MethodInterceptor) - 匹配当前方法的所有 Advisor,生成通知链(Interceptor 链)
- 通过
ReflectiveMethodInvocation的proceed()方法,递归执行通知链 - 执行顺序:
@Around前置 →@Before→ 目标方法 → (@AfterReturning/@AfterThrowing)→@After→@Around后置。
注 :
@After是最终通知,无论目标方法是否异常,都会在@AfterReturning或@AfterThrowing之后执行。
核心源码:通知链执行
java
// ReflectiveMethodInvocation
@Override
@Nullable
public Object proceed() throws Throwable {
// 1. 通知链执行完毕,执行目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 2. 拿到下一个拦截器,递归执行
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);
}
}
七、面试高频问题
1. AOP 代理生成在 Bean 生命周期的哪个阶段?
答 :正常场景下,生成于 Bean 生命周期「初始化阶段」的最后一步,即 BeanPostProcessor 的后置处理方法 postProcessAfterInitialization,该方法在初始化方法(@PostConstruct/init-method)执行完成后调用。
2. JDK 动态代理和 CGLIB 动态代理的核心区别?
答:
- JDK 动态代理基于接口实现,要求目标类必须实现接口,生成接口的实现类代理;CGLIB 基于继承实现,生成目标类的子类代理,要求目标类不能被 final 修饰。
- JDK 动态代理通过反射执行方法,在极高并发场景下性能略低于 CGLIB,常规业务场景差异不大。
- Spring 默认策略:目标类实现了接口用 JDK 代理,无接口用 CGLIB 代理,可通过
proxyTargetClass=true强制使用 CGLIB。
3. Spring AOP 内部调用为什么会失效?怎么解决?
答 :因为内部调用时,调用的是 this 原生对象,不是代理对象,不会触发切面逻辑。
解决方法:
- 开启
@EnableAspectJAutoProxy(exposeProxy = true) - 内部调用时,用
((当前类) AopContext.currentProxy()).目标方法(),通过代理对象调用。
4. @Aspect 切面的执行顺序怎么控制?
答 :通过 @Order 注解控制,value 值越小,优先级越高,执行顺序越靠前。前置通知优先级高的先执