人人都会AI编程

26.3 AOP 源码核心流程

更新时间:2026-07-10

理解了 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 为例,调用栈大致如下:

  1. @Around 拦截器执行前半段逻辑,然后调用 proceed()
  2. @Before 拦截器执行通知逻辑,然后调用 proceed()
  3. 链尾调用目标方法本身。
  4. 目标方法返回后,栈回退:@Around 的后半段逻辑执行,@AfterReturning@After 按顺序执行。

最后返回结果到最外层调用者。

26.3.4 核心类关系小结

| 类 / 接口 | 职责 |
| --- | --- |
| AnnotationAwareAspectJAutoProxyCreator | 注册到容器的 BeanPostProcessor,触发代理创建。 |
| AbstractAutoProxyCreator | 模板方法,提供 wrapIfNecessarycreateProxy。 |
| 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 的源码流程,不是要去记忆每一行实现,而是让你对“为什么这样写通知会执行在那个位置”有了清晰的认知,从而更自信地使用和诊断这个强大的工具。