连接点 (Join Point) 是什么?在 Spring AOP 中,连接点只能是什么?

连接点 (Join Point) 是什么?在 Spring AOP 中,连接点只能是什么?_第1张图片

什么是连接点 (Join Point)?

连接点 (Join Point) 是指在程序执行过程中,可以被切面(Aspect)的通知(Advice)所织入的所有可能的时间点或事件点


详细解释:

你可以把你的整个应用程序的执行流程想象成一条长长的时间线。在这条时间线上,会发生很多事情,比如:

  • 一个方法被调用。
  • 一个方法正在执行。
  • 一个对象被创建(构造函数被调用)。
  • 一个类的字段被读取或修改。
  • 一个异常被抛出。

所有这些在程序执行流程中可以被精确定义的“点”,都是连接点 (Join Point)。它们是 AOP 框架能够“插入”逻辑的候选位置

比喻:

  • 连接点 (Join Point):就像一个城市里所有的十字路口。理论上,你可以在任何一个十字路口设置交通信号灯。
  • 切点 (Pointcut):就像你制定的一个规则,比如“只在所有主干道的十字路口设置信号灯”。这个规则从所有的十字路口(Join Points)中筛选出了一部分。
  • 通知 (Advice):就是你要设置的交通信号灯本身(红灯停,绿灯行)。

所以,关系是:切点(Pointcut)在所有连接点(Join Points)中进行筛选,然后通知(Advice)被应用到被选中的连接点上。

从理论上讲,一个强大的 AOP 框架(如完整的 AspectJ)可以支持多种类型的连接点。


在 Spring AOP 中,连接点只能是什么?

这是一个非常关键的区别点,也是面试中经常被问到的问题。

答案:在 Spring AOP 中,连接点只支持方法执行 (Method Execution) 类型的连接点。

为什么会有这个限制?

这个限制源于 Spring AOP 的实现机制。Spring AOP 是基于代理 (Proxy) 模式实现的,主要有两种代理方式:

  1. JDK 动态代理:当你的目标类实现了接口时,Spring 会使用 JDK 的动态代理。它会创建一个实现了相同接口的代理类,这个代理类在调用目标方法之前之后可以插入自定义逻辑。
  2. CGLIB 代理:当你的目标类没有实现任何接口时,Spring 会使用 CGLIB。它会为目标类创建一个子类作为代理,并重写父类(目标类)的方法,从而在调用 super.method()前后插入逻辑。

共同点:无论是 JDK 动态代理还是 CGLIB,它们的核心都是在方法级别进行拦截和包装。代理对象无法知道也无法干预目标对象内部的字段访问、构造函数的调用或其他非方法执行的事件。

因此,Spring AOP 的能力被限制在了方法的入口和出口。它不能像 AspectJ 那样,在字段被访问时或构造函数执行时织入代码。

结论:

  • 我们不能用 Spring AOP 来拦截字段的读写操作。
  • 我们不能用 Spring AOP 在对象构造时添加逻辑。
  • 我们的切点表达式(Pointcut Expression)虽然语法上可能支持其他类型(如 get(), set(), init()),但在 Spring AOP 的环境中,它们实际上是无效的,只有 execution() 这类与方法执行相关的指示符才能真正生效。

总结与对比

为了更清晰地理解,我们来对比一下 Spring AOP 和更强大的 AspectJ:

特性 Spring AOP AspectJ
支持的连接点 仅支持方法执行 (Method Execution) 非常全面:方法执行、方法调用、构造函数执行、字段读/写、静态初始化等。
实现方式 基于运行时代理(JDK 动态代理 / CGLIB) 基于编译时加载时织入 (Weaving),直接修改字节码。
侵入性 低,无需特殊编译器或配置。 较高,需要 AspectJ 编译器(ajc)或类加载时织入代理。
性能 代理调用会带来轻微性能开销。 由于在编译期已将代码织入,运行时几乎没有额外开销,性能更高。
易用性 非常简单,与 Spring IoC 无缝集成。 相对复杂,需要额外的学习和配置成本。

结论:

连接点 (Join Point) 是一个广义的 AOP 概念,代表了所有可以织入代码的程序执行点。然而,在 Spring AOP 的具体实现中,由于其代理机制的限制,连接点实际上特指方法的执行。这是一种权衡,Spring 牺牲了 AOP 的部分功能性,换来了极大的易用性和与框架的无缝集成,这对于绝大多数业务场景(如事务、日志、安全)已经完全足够了。

你可能感兴趣的:(Spring,AOP,spring,java,后端,aop)