乐于分享
好东西不私藏

第四篇・Spring 5 源码深度拆解:AOP 全流程核心原理

第四篇・Spring 5 源码深度拆解:AOP 全流程核心原理

从切面解析到代理植入,彻底搞懂 AOP 底层逻辑
👋 前言

Spring IOC 核心链路:容器启动 → Bean 生命周期全流程 → 循环依赖与三级缓存

在 Bean 生命周期里:Bean 生命周期中,当 Bean 匹配到 Advisor 时,AOP 代理对象BeanPostProcessor 的 postProcessAfterInitialization 后置处理阶段生成(循环依赖场景下提前在 getEarlyBeanReference 生成)

这一篇,我们拆解 Spring AOP 的源码流程,从开启注解、解析切面,到代理生成、运行时执行:

  1. @EnableAspectJAutoProxy 到底做了什么?
  2. Spring 怎么扫描解析@Aspect切面、@Pointcut切点?
  3. 代理对象到底在 Bean 生命周期的哪个节点生成?
  4. JDK 动态代理和 CGLIB 动态代理怎么选?
  5. 循环依赖场景下,AOP 代理是怎么处理的?
  6. 运行时,切面通知的执行顺序是怎么控制的?

一、先搞懂核心前提: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 时,只需要加一个注解:

@Configuration@EnableAspectJAutoProxy // 开启AOP@ComponentScan("com.example")public classSpringConfig{}

这个注解,就是 AOP 所有逻辑的起点

1. 注解源码拆解

@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 容器中注册了一个核心 BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator

关键源码

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 接口

为什么它是核心?

  1. 它是一个BeanPostProcessor,会介入每一个 Bean 的生命周期
  2. 它负责:扫描解析所有@Aspect切面,生成 Advisor
  3. 它负责:判断 Bean 是否需要生成代理,生成代理对象
  4. 它就是我们第二篇 Bean 生命周期里,后置处理器中生成 AOP 代理的那个类

三、AOP 全流程第一阶段:容器启动时,切面解析与 Advisor 生成

Spring AOP 不是 Bean 创建时才解析切面,而是容器启动时,就提前扫描解析所有切面,生成 Advisor 通知器,对应我们第一篇的容器启动流程。

完整流程

  1. 容器启动,执行refresh()
  2. 执行invokeBeanFactoryPostProcessors(),解析@EnableAspectJAutoProxy,注册AnnotationAwareAspectJAutoProxyCreator
  3. 执行registerBeanPostProcessors(),把AnnotationAwareAspectJAutoProxyCreator实例化,加入到 BeanPostProcessor 列表中
  4. AnnotationAwareAspectJAutoProxyCreator
     提前扫描所有@Aspect注解的类,解析切点、通知,封装成一个个Advisor对象,缓存起来,供后续 Bean 创建时使用

核心源码:切面解析

// AnnotationAwareAspectJAutoProxyCreator 核心方法protected List<AdvisorfindCandidateAdvisors() {    // 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. 入口:后置处理方法

// AbstractAutoProxyCreator(父类)@Overridepublic Object postProcessAfterInitialization(@NullableObject bean, String beanName) {    if (bean != null) {        Object cacheKey = getCacheKey(bean.getClass(), beanName);        // 核心:判断是否需要生成代理,需要则返回代理对象,否则返回原生Bean        return wrapIfNecessary(bean, beanName, cacheKey);    }    return bean;}

2. 核心判断:wrapIfNecessary(要不要生成代理)

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

protected Object createProxy(Class<?> beanClass, @NullableString 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?

// DefaultAopProxyFactory@Overridepublic 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 代理:

  1. A 实例化后,暴露工厂到三级缓存
  2. B 创建时,需要注入 A,从三级缓存拿到 A 的工厂,执行getEarlyBeanReference
  3. 这里会提前生成 A 的 AOP 代理对象,注入到 B 中
  4. A 后续初始化完成后,不会再重复生成代理,保证单例

核心源码

// AbstractAutoProxyCreator@Overridepublic 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 通过责任链模式控制通知的执行顺序。

核心执行流程

  1. 调用代理对象的目标方法
  2. 进入代理对象的拦截器(JDK 的InvocationHandler/CGLIB 的MethodInterceptor
  3. 匹配当前方法的所有 Advisor,生成通知链(Interceptor 链)
  4. 通过ReflectiveMethodInvocationproceed()方法,递归执行通知链
  5. 执行顺序:@Around 前置 → @Before → 目标方法 → (@AfterReturning / @AfterThrowing)→ @After → @Around 后置。
    注:@After 是最终通知,无论目标方法是否异常,都会在 @AfterReturning 或 @AfterThrowing 之后执行。

核心源码:通知链执行

// ReflectiveMethodInvocation@Override@Nullablepublic 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原生对象,不是代理对象,不会触发切面逻辑。

解决方法:

  1. 开启@EnableAspectJAutoProxy(exposeProxy = true)
  2. 内部调用时,用((当前类) AopContext.currentProxy()).目标方法(),通过代理对象调用。

4. @Aspect 切面的执行顺序怎么控制?

答:通过@Order注解控制,value值越小,优先级越高,执行顺序越靠前。前置通知优先级高的先执行,后置通知优先级高的后执行。

八、AOP 完整链路精简版
1. @EnableAspectJAutoProxy 开启AOP,注册核心处理器        ↓2. 容器启动,扫描@Aspect切面,解析生成Advisor        ↓3. Bean创建,初始化完成后,进入后置处理器        ↓4. 匹配Advisor,判断是否需要代理,需要则生成代理对象        ↓5. 代理对象替换原生Bean,放入单例池        ↓6. 运行时调用方法,触发拦截器,执行通知链

九、可直接断点调试的 AOP 完整项目

1. pom.xml 依赖

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.example</groupId>    <artifactId>spring-aop-debug</artifactId>    <version>1.0-SNAPSHOT</version>    <properties>        <spring.version>5.3.37</spring.version>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aop</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>            <version>1.9.21</version>        </dependency>    </dependencies></project>

2. 项目结构

src├── main│   └── java│       └── com│           └── example│               └── aopdebug│                   ├── config│                   │   └── SpringAopConfig.java│                   ├── service│                   │   ├── UserService.java│                   │   └── UserServiceImpl.java│                   ├── aspect│                   │   └── LogAspect.java│                   └── AopDebugApplication.java└── pom.xml

3. 完整代码

配置类 SpringAopConfig.java

package com.example.aopdebug.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration@ComponentScan(basePackages = "com.example.aopdebug")@EnableAspectJAutoProxypublic class SpringAopConfig {}

业务接口 UserService.java

package com.example.aopdebug.service;public interface UserService {    void addUser(String username);}

业务实现类 UserServiceImpl.java

package com.example.aopdebug.service;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl implements UserService {    @Override    public void addUser(String username) {        System.out.println("【目标方法执行】正在添加用户:" + username);    }}

切面类 LogAspect.java

package com.example.aopdebug.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;@Aspect@Componentpublic class LogAspect {    @Pointcut("execution(* com.example.aopdebug.service.*.*(..))")    public void servicePointcut() {}    @Before("servicePointcut()")    public void before() {        System.out.println("【前置通知 @Before】方法执行前");    }    @AfterReturning("servicePointcut()")    public void afterReturning() {        System.out.println("【后置返回通知 @AfterReturning】方法正常返回");    }    @After("servicePointcut()")    public void after() {        System.out.println("【最终通知 @After】方法执行完毕");    }    @Around("servicePointcut()")    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {        System.out.println("【环绕通知 @Around 前置】方法执行前");        Object result = joinPoint.proceed();        System.out.println("【环绕通知 @Around 后置】方法执行后");        return result;    }}

启动调试类 AopDebugApplication.java

package com.example.aopdebug;import com.example.aopdebug.config.SpringAopConfig;import com.example.aopdebug.service.UserService;import org.springframework.aop.support.AopUtils;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class AopDebugApplication {    public static void main(String[] args) {        AnnotationConfigApplicationContext context =                new AnnotationConfigApplicationContext(SpringAopConfig.class);        UserService userService = context.getBean(UserService.class);        // 查看代理对象信息        System.out.println("Bean真实类型:" + userService.getClass().getName());        System.out.println("是否是AOP代理:" + AopUtils.isAopProxy(userService));        System.out.println("是否是JDK代理:" + AopUtils.isJdkDynamicProxy(userService));        System.out.println("是否是CGLIB代理:" + AopUtils.isCglibProxy(userService));        // 触发AOP通知执行        userService.addUser("张三");        context.close();    }}

4. 核心断点位置

断点类全称

断点方法

调试内容

AnnotationAwareAspectJAutoProxyCreator

findCandidateAdvisors()

切面解析与 Advisor 生成

 AbstractAutoProxyCreator  

 postProcessAfterInitialization()

代理生成入口

 AbstractAutoProxyCreator  

wrapIfNecessary()

代理匹配判断

 DefaultAopProxyFactory  

createAopProxy()

代理类型选择

 JdkDynamicAopProxy  

invoke()

运行时通知链执行

下篇预告

下一篇我们进入 Spring 最核心的业务场景考点:

Spring 事务源码全流程拆解

  • @Transactional 注解到底做了什么?
  • 事务的传播行为、隔离级别源码实现
  • 事务失效的 9 种场景,从源码层面说清为什么
  • 事务与 AOP 的关联关系

如您在文章中发现有错误的地方,欢迎指正。