欢迎来到@边境矢梦°的csdn博文
本文主要梳理 Spring 中的切面编程aop的底层原理和重点注意的地方
我是边境矢梦°,一个正在为秋招和算法竞赛做准备的学生
喜欢的朋友可以关注一下,下次更新不迷路
Ps: 月亮越亮说明知识点越重要 (重要性或者难度越大)
目录
❤️切面编程介绍
连接点和切入点的区别
Spring中扫描包注册bean
✨Spring中切面编程的两种实现
切入表达式
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切入点表达式语言编写的,它具有灵活的语法,可以根据需求选择不同的连接点。(下文中)
切面类不需要扫描进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来应用切面时,以下是通常的流程:
你定义了一个切面类,该类使用 @Aspect
注解进行标记,同时定义了切面逻辑,如@Before、@After等通知。
你还定义了一个或多个目标bean,这些bean是你的应用程序的组成部分,切面将会应用到这些bean的方法上。
Spring容器会扫描并加载这些目标bean,将它们实例化并管理它们的生命周期。
你配置Spring AOP,告诉Spring在哪些切点(方法执行点)应用你的切面。这通常通过
或 @EnableAspectJAutoProxy
这样的配置来完成。
Spring会自动为目标bean创建代理对象,这些代理对象包含了切面逻辑。当你调用目标bean的方法时,切面逻辑会在方法执行前后生效,从而实现横切关注点的功能。
所以,虽然切面类本身不需要被显式注册为Spring bean,但目标bean需要被Spring加载并纳入容器管理,以便切面可以应用到它们的方法上。这就是Spring AOP的工作原理。
在Spring AOP中,不仅可以对实现了接口的bean进行切面编程,还可以对没有实现接口的bean进行切面编程。Spring使用代理对象来实现AOP,而代理对象可以基于接口(JDK动态代理)或基于类(CGLIB代理)创建,因此不需要目标bean实现接口也可以应用切面。
具体取决于AOP代理的方式:
JDK动态代理:当目标bean实现了接口时,Spring会使用JDK动态代理来创建代理对象。这意味着只有实现了接口的方法才能被切面所影响。
CGLIB代理:当目标bean没有实现接口时,Spring会使用CGLIB代理来创建代理对象。CGLIB可以代理没有实现接口的类,因此可以应用到这些类的方法。
✍️两个动态代理的区别
- JDK动态代理是面向接口的,只能增强实现类中接口中存在的方法。CGlib是面向父类的,可以增强父类的所有方法
- JDK得到的对象是JDK代理对象实例,而CGlib得到的对象是被代理对象的子类
要注意的是,如果你使用基于注解的切面编程(例如使用 @Aspect
注解),Spring AOP会自动选择适当的代理方式,无需手动指定。只需确保你的切面和目标bean都配置正确,Spring会处理代理的创建和切面的应用。
所以,Spring AOP可以用于实现对实现接口和未实现接口的bean的切面编程。选择代理方式取决于目标bean是否实现了接口。
图来自 : (III)AOP:第四节:切入点表达式 - 格物致知_Tony - 博客园 (cnblogs.com)
切入点表达式
作用
通过表达式的方式定位一个或多个具体的连接点。
语法细节
①切入点表达式的语法格式
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方法 |