Spring源码解析系列(三)Spring AOP 原理与 CGLIB / JDK 动态代理源码分析

共计 2323 个字符,预计需要花费 6 分钟才能阅读完成。

一、前言

Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架中实现横切逻辑(如事务、安全、日志)不可或缺的模块。

容易遇到的问题:

  • 为什么有时代理类是 $Proxy0,有时是 com.xx$$EnhancerBySpringCGLIB
  • 接口与类的代理方式有什么区别?
  • AOP 是怎么织入代码的?Spring 是何时生成代理对象的?
  • AOP 的执行链是如何维护的?

本篇文章将以源码为主线,全面解析 Spring AOP 的原理,深入理解 JDK 动态代理与 CGLIB 的实现机制。

二、Spring AOP 是什么?

Spring AOP 是基于 代理模式 实现的,将横切逻辑织入目标对象的执行流程中,核心是对目标 Bean 生成代理对象。

关键点:

  • 本质是一个 动态代理对象(实现了目标类的接口或子类)
  • 通过 AOP 拦截器链(MethodInterceptor)来增强目标方法
  • 默认采用 运行时增强(非编译期织入)

三、Spring AOP 代理创建过程

1.入口注解@EnableAspectJAutoProxy

@Configuration
@EnableAspectJAutoProxy
public class AopConfig { … }

这个注解的作用是启用基于注解的 AOP 功能,它最终引入了:

@Import(AspectJAutoProxyRegistrar.class)

注册了核心组件:

AnnotationAwareAspectJAutoProxyCreator

它是一个实现了 BeanPostProcessor 接口的类,用来在 Bean 初始化后判断是否需要生成代理。

2. 关键类:AnnotationAwareAspectJAutoProxyCreator

其中核心方法是:

public Object postProcessAfterInitialization(Object bean, String beanName) {
    return wrapIfNecessary(bean, beanName, cacheKey);
}

3.wrapIfNecessary 方法

判断当前 bean 是否需要增强,如果需要则调用 createProxy() 创建代理对象:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        return bean;
    }

    // 获取切面匹配的通知器(Advisor)
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(...);

    if (specificInterceptors != DO_NOT_PROXY) {
        return createProxy(bean.getClass(), beanName, specificInterceptors, ...);
    }

    return bean;
}

四、JDK 动态代理与 CGLIB 区别与源码分析

Spring AOP 默认会根据目标类是否实现了接口自动选择:

场景 代理方式 关键类
目标类实现了接口 使用 JDK 动态代理 JdkDynamicAopProxy
目标类未实现接口 使用 CGLIB 代理 CglibAopProxy

五、拦截器链执行流程(重要)

无论是 JDK 代理还是 CGLIB,Spring 最终都构建一个拦截器链(MethodInterceptor),然后顺序执行。

流程如下:

MethodInterceptor1 -> MethodInterceptor2 -> … -> 目标方法执行 -> 返回结果

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptors.size() - 1) {
        return invokeJoinpoint(); // 调用目标方法
    }

    MethodInterceptor interceptor = this.interceptors.get(++currentInterceptorIndex);
    return interceptor.invoke(this);
}

常见的拦截器有:

  • TransactionInterceptor(事务)
  • MethodBeforeAdviceInterceptor(前置通知)
  • AspectJAfterReturningAdvice(后置通知)
  • AspectJAfterThrowingAdvice(异常通知)

六、完整执行流程图

(还没画完 后续补上)

七、总结

Spring AOP 为我们提供了极为灵活和强大的面向切面能力。深入理解其代理机制、拦截器执行流程、动态代理原理,不仅有助于我们写出高质量、可维护的业务代码,更能让我们在调试与排障中得心应手。

八、关注后续专栏

本文是《Spring 源码解析系列》专栏的第 3 篇,后续将发布:

  • 《Spring 中的事件监听机制(ApplicationEvent)源码与实战》
  • 《Spring Bean 的循环依赖原理(三级缓存)深入分析》

附录:参考源码位置

  • AnnotationAwareAspectJAutoProxyCreator.java
  • JdkDynamicAopProxy.java
  • CglibAopProxy.java
  • ReflectiveMethodInvocation.java
  • MethodInterceptor.java

如果本文对你有帮助,欢迎点赞、评论、收藏!我是 李卷卷,专注Java相关知识输出。感谢阅读!

正文完
 0
李卷卷
版权声明:本站原创文章,由 李卷卷 于2023-07-12发表,共计2323字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)