关于springAOP的总结

12.4号14:01我终于整理完笔记,理清了所有知识点。

关于spring的两大核心:Ioc和AOP

AOP的底层:动态代理技术

为什么要有AOP?

一般一个系统当中都会有一些系统服务,例如:日志、事务管理、安全等。这些系统服务被称为:交叉业务

这些交叉业务几乎是通用的,不管你是做银行账户转账,还是删除用户数据。日志、事务管理、安全,这些都是需要做的。

这会产生什么问题?

  • 代码的复用性差。
  • 交叉业务与核心业务书写在一起,后期维护难。

AOP做了什么?

为了让代码客户端专注于核心业务代码,也方便维护,从纵向的核心业务把重复的横向业务代码抽离出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的过程被称为AOP。

AOP底层的实现

AOP底层是靠JDK的自带的动态代理技术和CGLIB的动态代理实现的

  • JDK 动态代理主要用于对接口进行代理,其底层通过在运行时内存中动态生成一个实现了目标
    接口的代理类字节码,并借助 InvocationHandler 实现方法拦截。
  • CGLIB 通过在运行时动态生成目标类的子类(代理类)来实现对类的代理,其底层基于字节码 生成技术,通过继承并重写非 final 方法以插入代理逻辑。
  • 补充:即使目标类有接口,你也可以强制 Spring 使用 CGLIB(通过配置 proxyTargetClass true)。

!NOTE\] 前面静态代理中不是说继承的耦合度高吗,为啥CGLIB使用继承实现了动态代理? 它在内存中生成,无关业务代码,也就不存在这类问题。

AOP实现的细节

Spring AOP 的实现细节可以简要概括为以下几点:

  1. 基于代理

    Spring AOP 不修改字节码,而是在运行时为目标 Bean 创建代理对象(JDK 动态代理或 CGLIB),通过代理拦截方法调用。

  2. 代理选择

    • 目标类实现了接口 → 默认使用 JDK 动态代理
    • 无接口或配置 proxyTargetClass=true → 使用 CGLIB 代理
  3. 织入时机

    在 Bean 初始化完成后,由 BeanPostProcessor(如 AnnotationAwareAspectJAutoProxyCreator)判断是否需要代理,并将代理对象放入 Spring 容器,替换原始 Bean。

  4. 通知执行

    方法调用时,代理对象通过 责任链模式 依次执行各类通知(@Before@Around@After 等),最后调用目标方法(通过反射)。

  5. 统一适配

    所有通知类型(如 MethodBeforeAdvice)最终都被适配成 MethodInterceptor,统一在拦截链中执行。

  6. 局限性

    只能拦截 public 方法 ,且 self-invocation(内部调用)不会触发 AOP,因为调用的是 this 而非代理对象。

总结:Spring AOP = 动态代理 + BeanPostProcessor + 责任链 + 反射,全程在运行时完成,对业务代码无侵入。

Spring AOP 的实现流程

1. 启动时扫描切面

  • Spring 容器启动时,通过 @EnableAspectJAutoProxy(或 XML 配置)注册一个特殊的 BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator
  • 它会识别所有带 @Aspect 注解的类,并解析其中的 @Before@After@Around 等通知,转换成 Advisor(包含 Pointcut + Advice)

2. Bean 初始化后判断是否需要代理

  • 当每个 Bean 初始化完成后,上述 BeanPostProcessorpostProcessAfterInitialization() 方法被调用。
  • 它检查该 Bean 的类和方法是否匹配已有的 Pointcut 表达式
  • 如果匹配,就进入代理创建流程。

3. 选择代理方式并创建代理对象

  • 判断目标类是否有接口:
    • 有接口 → 默认用 JDK 动态代理 (生成 $Proxy0 类)
    • 无接口 或 开启 proxyTargetClass=true → 使用 CGLIB (生成 Xxx$$EnhancerBySpringCGLIB$$... 子类)
  • 创建代理对象,内部持有原始目标对象 + 所有匹配的 Advisor 列表。

4. 将代理对象放入容器

  • 这个容器就是 Spring 的 IoC 容器本身
  • 容器中保存的是 代理对象,而不是原始 Bean。
  • 后续所有对该 Bean 的依赖注入或获取,都返回这个代理。

5. 调用方法时触发拦截链

  • 当调用代理对象的方法时:
    • JDK 代理 → 调用 InvocationHandler.invoke()
    • CGLIB 代理 → 调用 MethodInterceptor.intercept()
  • 两者都会构建一个 MethodInvocation 对象,内部包含:目标方法、参数、通知链(List)。

6. 按顺序执行通知 + 目标方法

  • 调用 methodInvocation.proceed(),以 责任链模式 依次执行:
    1. @Before 通知
    2. @Around 的前半部分
    3. 目标方法(通过反射调用)
    4. @Around 的后半部分
    5. @AfterReturning(成功)或 @AfterThrowing(异常)
    6. @After(最终通知,类似 finally)

相关推荐
rannn_1116 分钟前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
qq_124987075310 分钟前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
短剑重铸之日16 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼191939 分钟前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王1 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)1 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
码农小卡拉1 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
向上的车轮1 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net
Dragon Wu1 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
跳动的梦想家h1 小时前
环境配置 + AI 提效双管齐下
java·vue.js·spring