相关推荐recommended
【Spring】aop的底层原理
作者:mmseoamin日期:2023-12-18

🎄欢迎来到@边境矢梦°的csdn博文🎄

 🎄本文主要梳理 Spring 中的切面编程aop的底层原理和重点注意的地方 🎄

🌈我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生🌈

🎆喜欢的朋友可以关注一下🫰🫰🫰,下次更新不迷路🎆

Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大)🌑🌒🌓🌔🌕  

【Spring】aop的底层原理,第1张

 

目录

❤️切面编程介绍

🌸连接点和切入点的区别🚀

🌈Spring中扫描包注册bean

✨Spring中切面编程的两种实现

🎈切入表达式


【Spring】aop的底层原理,第2张

❤️切面编程介绍

🎈Spring的切面编程是通过AOP(面向切面编程)机制来实现。AOP是一种编程范式,旨在将横切关注点(如日志记录、事务管理等)与核心业务逻辑分离,以提高代码的模块性、可重用性和可维护性。

在Spring中,切面由两部分组成:切点(Pointcut)和通知(Advice)。

📌切点定义了在哪些连接点上应用切面逻辑。连接点是程序执行过程中可以插入切面逻辑的特定点,例如方法的执行、方法的调用等。切点可以使用表达式来选择特定的连接点,可以根据方法名、类名、注解等条件进行选择。

📌通知是切面逻辑的具体实现。它定义了在切点上要执行的行为,可以在切点的前后、异常抛出时、方法返回时等时机执行。常见的通知类型包括前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)和返回通知(AfterReturning)等。

✍️除了切点和通知,切面还可以包括引入(Introduction)和切面顺序(Aspect Ordering)等功能。引入允许在现有类中添加新的方法和属性,以增强类的功能。切面顺序定义了多个切面的执行顺序,以控制切面逻辑的执行顺序。

在Spring中,切面可以通过XML配置、基于注解的配置或者基于Java的配置来定义。Spring提供了多种AOP实现,✨包括基于JDK的动态代理和基于CGlib的字节码生成。

🎉通过使用Spring的切面编程,可以将共同的横切关注点从核心业务逻辑中剥离出来,以提高代码的可维护性和可重用性。切面编程在日志记录、事务管理、安全性控制等方面有广泛的应用。


🌸连接点和切入点的区别🚀

在Spring框架的AOP编程中,连接点(Join Point)和切入点(Pointcut)是两个相关但不同的概念。

📌连接点是在程序执行过程中,可以插入切面逻辑的特定点。这些点可以是方法的执行、方法的调用或者异常的抛出等。在Spring中,连接点通常是方法的执行。连接是bean中的一些点

📌切入点是指在连接点中选择特定的连接点。它是一个表达式,描述了哪些连接点将被切面逻辑所应用。切入点可以根据方法名、类名、注解等条件来选择特定的连接点。

换句话说,切入点是一个定义,它决定了在哪些连接点上切面逻辑将会被执行。连接点是实际的程序执行点(Bean的),而切入点是定义了在哪些连接点上应用切面逻辑的规则。

🌰例如,可以通过切入点表达式来选择在所有的Service接口的方法执行时应用切面逻辑。而连接点则是具体的某个Service接口的方法执行。

在Spring AOP中,切入点表达式是使用AspectJ切入点表达式语言编写的,它具有灵活的语法,可以根据需求选择不同的连接点。(下文中)


🌈Spring中扫描包注册bean

🥝切面类不需要扫描进bean

在Spring中,当你使用 进行包扫描时,它默认会扫描指定包及其子包中的类,并将带有特定注解的类注册为Spring容器中的bean。如果类没有加上注解,它将不会被注册为bean,也就不会被Spring进行管理。

然而,与AOP(面向切面编程)有关的切面通常不需要被注册为bean,因为它们是通过特定的AOP配置来创建和管理的。切面通常是带有 @Aspect 注解的类,并且它们的方法可以使用 @Before、@After 等注解来定义切面逻辑。

所以,如果你的切面类(带有 @Aspect 注解的类)在指定的包中,它会被扫描到,但不会被注册为Spring容器中的bean。相反,Spring会使用AOP配置来创建并管理这些切面,例如使用 或 @EnableAspectJAutoProxy 这样的配置来启用自动代理,从而将切面应用到相应的bean中。

总之,不需要将切面类注册为Spring bean,Spring会自动处理AOP相关的配置和代理生成。只需确保切面类在扫描的包中以及AOP配置正确即可。

🥝切面应用到的目标bean需要被扫描进bean

切面应用到的目标bean通常需要被Spring加载进容器中,以便Spring可以管理这些bean并应用切面的横切关注点(cross-cutting concerns)。

🏀总结切面的流程

具体来说,当你使用Spring AOP来应用切面时,以下是通常的流程:

  1. 你定义了一个切面类,该类使用 @Aspect 注解进行标记,同时定义了切面逻辑,如@Before、@After等通知。

  2. 你还定义了一个或多个目标bean,这些bean是你的应用程序的组成部分,切面将会应用到这些bean的方法上。

  3. Spring容器会扫描并加载这些目标bean,将它们实例化并管理它们的生命周期。

  4. 你配置Spring AOP,告诉Spring在哪些切点(方法执行点)应用你的切面。这通常通过 或 @EnableAspectJAutoProxy 这样的配置来完成。

  5. Spring会自动为目标bean创建代理对象,这些代理对象包含了切面逻辑。当你调用目标bean的方法时,切面逻辑会在方法执行前后生效,从而实现横切关注点的功能。

所以,虽然切面类本身不需要被显式注册为Spring bean,但目标bean需要被Spring加载并纳入容器管理,以便切面可以应用到它们的方法上。这就是Spring AOP的工作原理。


✨Spring中切面编程的两种实现

在Spring AOP中,不仅可以对实现了接口的bean进行切面编程,还可以对没有实现接口的bean进行切面编程。Spring使用代理对象来实现AOP,而代理对象可以基于接口(JDK动态代理)或基于类(CGLIB代理)创建,因此不需要目标bean实现接口也可以应用切面。

具体取决于AOP代理的方式:

  1. JDK动态代理:当目标bean实现了接口时,Spring会使用JDK动态代理来创建代理对象。这意味着只有实现了接口的方法才能被切面所影响。

  2. CGLIB代理:当目标bean没有实现接口时,Spring会使用CGLIB代理来创建代理对象。CGLIB可以代理没有实现接口的类,因此可以应用到这些类的方法。

✍️两个动态代理的区别

  1. JDK动态代理是面向接口的,只能增强实现类中接口中存在的方法。CGlib是面向父类的,可以增强父类的所有方法
  2. JDK得到的对象是JDK代理对象实例,而CGlib得到的对象是被代理对象的子类

📌要注意的是,如果你使用基于注解的切面编程(例如使用 @Aspect 注解),Spring AOP会自动选择适当的代理方式,无需手动指定。只需确保你的切面和目标bean都配置正确,Spring会处理代理的创建和切面的应用。

所以,Spring AOP可以用于实现对实现接口和未实现接口的bean的切面编程。选择代理方式取决于目标bean是否实现了接口。

🎈切入表达式

📌图来自 : (III)AOP:第四节:切入点表达式 - 格物致知_Tony - 博客园 (cnblogs.com)

【Spring】aop的底层原理,第3张

 切入点表达式

🥝作用

通过表达式的方式定位一个或多个具体的连接点。

🌸🌈语法细节

①切入点表达式的语法格式

execution([权限修饰符][返回值类型][简单类名/全类名][方法名]([参数列表]))

②🌰 基本使用

表达式execution(* com.sina.spring.ArithmeticCalculator.*(..))
含义

ArithmeticCalculator接口中声明的所有方法。

第一个“*”代表任意修饰符及任意返回值。

第二个“*”代表任意方法。

“..”匹配任意数量、任意类型的参数。

若目标类、接口与该切面类在同一个包中可以省略包名。

表达式execution(public * ArithmeticCalculator.*(..))
含义ArithmeticCalculator接口的所有公有方法
表达式execution(public double ArithmeticCalculator.*(..))
含义ArithmeticCalculator接口中返回double类型数值的方法
表达式execution(public double ArithmeticCalculator.*(double,..))
含义

第一个参数为double类型的方法。

“..”匹配任意数量、任意类型的参数。

表达式execution(public double ArithmeticCalculator.*(double, double))
含义参数类型为double,double类型的方法
表达式execution(* *.add(int,….)) l execution(* *.sub(int,..))
含义任意类中第一个参数为int类型的add方法或sub方法