【spring】springAOP

ops/2025/3/13 20:44:11/

1.基本概念

AOP即面向切面编程,它利用的是一种横切技术,解剖开封装的对象内部,并将那些影响多个类的公共行为封装到一个可重 用模块,这就是所谓的Aspect方面/切面。所谓的切面,简单点所说,就是将哪些与业务无关,却为业务 模块所共同调用的行为(方法)提取封装,减少系统的重复代码,以达到逻辑处理过程中各部分之间低 耦合的隔离效果。

Spring AOP 的实现基于动态代理技术(JDK 或 CGLIB),但为了简化开发,它引入了 AspectJ 的注解模型(如@Aspect@Pointcut等),从而支持更简洁的切面定义。

    2.AOP相关术语

    切面:切面就是对横切关注点进行模块化封装的一种方式,在SpringAop中就是一个类。例如要实现一个登录页面的功能,但是我想要在登录前进行权限的验证,判断你是管理员还是用户,此时不可能直接把这个功能直接写在登录页面的功能里,会提高耦合性,所以就可以另写一个类将权限验证的功能封装。

    在SpringAop中用@Aspect对相关类标记为切面。

    连接点:连接点指的是程序执行过程中可以插入切面的特定位置。在 Spring AOP 中,连接点仅支持方法执行这一种情况,也就是在某个方法调用或者方法执行前后这些时间点。

    还是上面的例子,当你准备执行登录的方法时,该方法就是一个连接点,切面中实现的登录验证就可以在该方法前执行。

    切点:切点是用于匹配连接点的表达式,它定义了哪些连接点会被应用通知。通过切点表达式,可以精确地筛选出需要增强的方法。它就是用来定位那些被增强的方法,使得通知能够准确的应用到目标方法(也就是这些被增强的方法)

    这里的被增强的方法就是那些被切面分装了相关方法准备在该方法前后执行,就比如登录方法多了个权限验证功能,那么这个登录方法就是被增强的方法。

    spring中用@Pointcut来指定相应的包进行扫描,来定位包中的方法是否为被增强的方法,它有一个切点表达式,来负责筛选被增强的方法。

    切点表达式的定义如下

    @Pointcut(“execution([修饰符] 返回类型 [包名..][类名.]方法名([参数]))”)

    修饰符:可选(如publicprivate),可省略。

    返回类型:必须,用*表示任意返回类型。

    包名com.example.service表示特定包;com.example..表示递归匹配子包。

    类名UserService表示特定类;*Service表示类名以Service结尾。

    方法名saveUser表示特定方法;*表示所有方法。

    参数(User)表示参数为User类型;(..)表示任意数量参数。

    通知:通知就是规定在切点即被增强的方法执行方法的逻辑,就比如前面说到的又在登录功能前加上一个权限验证的方法,通知就是用来规定权限验证功能必须在登录前执行,而不是登录后执行,也就是规定了执行的逻辑。

    下面列举几种通知的类型(结合spring的注解)

    @Before:前置通知,就是在切点执行前执行

    @AfterReturning:返回后通知,就是在切点正常执行后执行

    @AfterThrowing:异常后通知,就是在切点执行时出现异常时执行

    @After:后置通知(最终通知),无论切点是正常执行还时执行时出现异常,它都会在他后执行,相当于是个收尾的执行。

    @Around:环绕通知,它会完全包裹切点的执行,可以在它执行前后进行执行,甚至可以控制切点执行与否以及如何执行,也就是说它对切点执行前后都有控制权。

    目标对象:目标对象指的是包含核心业务逻辑的原始对象,也就是被一个或多个切面所增强的对象。简单来说,就是我们希望对其方法进行额外功能增强(如添加日志记录、事务管理等)的那个对象。

    代理:代理是指 Spring AOP 为目标对象生成的一个包装对象,该对象与目标对象具有相同的接口(对于 JDK 动态代理)或者继承自目标对象(对于 CGLIB 代理)。代理对象会拦截对目标对象方法的调用,并在调用前后插入切面中定义的通知逻辑,从而实现对目标对象方法的增强。

    在 Spring AOP 中,通过@EnableAspectJAutoProxy注解启用自动代理功能,Spring 会根据目标对象是否实现接口来选择使用 JDK 动态代理还是 CGLIB 代理。也可以通过proxyTargetClass属性强制使用 CGLIB 代理:

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication
    @EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB代理
    public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
    }

    织入:

    织入是 AOP 的核心步骤,它将切面中定义的切点(Pointcut)和通知(Advice)与目标对象的方法进行关联,使得在目标方法执行时,通知逻辑能够被触发。

    织入的时机
    AOP 框架的织入可以发生在以下阶段:

    编译时(Compile-time Weaving):在目标类编译时进行织入(如 AspectJ)。
    类加载时(Load-time Weaving):在目标类被加载到 JVM 时进行织入(如 AspectJ 的 LTW)。
    运行时(Runtime Weaving):在程序运行时通过动态代理动态织入(如 Spring AOP)。

    引入:

    引入本质上是一种类型级别的增强,它打破了传统面向对象编程中类的功能固定性,通过 AOP 的方式,在运行时为类添加额外的接口实现,从而让类拥有新的行为和状态。

    在 Spring AOP 中,引入主要通过 @DeclareParents 注解来实现。该注解可以指定一个接口,让目标类实现这个接口,并提供一个默认的实现类,从而为目标类添加新的方法。

    使用上面那些注解时需要现在xml文件中开启spring对aop的注解支持

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    要把它定义再bean标签中 

    3.SpringAOP实现事务管理

    当我们要对数据库进行CRUD操作时,如果不对其进行事务管理,那么数据库无疑就是在“裸奔”,会出现各种各样的问题,如事务一致性,原子性等遭到破坏,在spring中也是同样的,只要涉及到对数据库的操作时,事务管理是必要的的。

    在具体讲之前,先回忆一下数据库的基础事务操作

    START:开启事务,显示启动事务,后续的sql操作会被视为事务的一部分

    COMMIT:提交事务,将所有的操作保存到数据库中,提交后,数据不可变更,不允许滚回。

    ROLLBACK:回滚事务,撤销事务中所有未提交的操作,回滚到事务开启前的状态。

    SAVEPOINT:保存点,在事务中设置中间保存点,允许部分回滚到该点。

    下面详细讲解具体的操作

    3.1maven相关依赖配置

    具体依赖如下

    <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>spring-transaction-aop-example</artifactId><version>1.0-SNAPSHOT</version><properties><!-- Spring 版本 --><spring.version>6.1.4</spring.version><!-- AspectJ 版本 --><aspectj.version>1.9.20</aspectj.version><!-- MySQL 驱动版本 --><mysql.version>8.2.0</mysql.version></properties><dependencies><!-- Spring Context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><!-- Spring AOP --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><!-- Spring Transaction --><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><!-- AspectJ Weaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectj.version}</version></dependency><!-- Spring JDBC --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!-- MySQL 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><source>17</source><target>17</target></configuration></plugin></plugins></build>
    </project>

    3.2配置数据源

    spring相关的xml文件中的bean标签内配置相关数据库的具体信息,以便能够连上数据库。

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="password"/>
    </bean>

    写在这里比直接写在具体的代码中更加方便后期的修改与维护,而不用直接在代码中去修改。

    3.3配置事务资源管理器

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
    </bean>

    它这里将数据源注入了事务资源管理器,这样事务资源管理器就知道从哪个数据源获取数据库连接来进行事务管理。

    3.4配置事务管理

    <!-- 启用声明式事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    在需要管理的业务方法上添加@Transactional,基础使用如下

    @Transactional
    public void saveOrder() {// 数据库操作(增删改)orderDao.insert(order);userDao.updateBalance(userId, amount);
    }

    他会在方法正常执行后自动提交,出现异常时自动回滚。

    扩展配置如下:通过相关参数来定制事务

    propagation事务传播行为(默认REQUIRED
    isolation事务隔离级别(默认DEFAULT
    rollbackFor指定需要回滚的异常类型(如SQLException.class
    timeout事务超时时间(秒)
    readOnly是否为只读事务(默认false
    @Transactional(propagation = Propagation.REQUIRES_NEW, // 强制新建事务isolation = Isolation.SERIALIZABLE,    // 最高隔离级别rollbackFor = Exception.class,         // 回滚所有异常timeout = 30                           // 超时时间30秒
    )
    public void criticalOperation() { ... }

    3.5注意事项

    1. 注解作用域@Transactional仅对public方法有效。
    2. 内部调用问题:类内部方法调用被注解的方法时,事务不会生效(需通过代理对象调用)。

    3.6底层原理

    Spring 通过AOP 动态代理实现事务织入:

    1. 代理创建:Spring 为目标类生成代理对象(JDK 或 CGLIB 代理)。
    2. 方法拦截:代理对象拦截被@Transactional标记的方法调用。
    3. 事务逻辑
      • 调用方法前:开启事务(beginTransaction)。
      • 方法正常执行后:提交事务(commit)。
      • 方法抛出异常时:回滚事务(rollback)。

     


    http://www.ppmy.cn/ops/165509.html

    相关文章

    蓝桥杯省赛真题C++B组-裁纸刀2022

    一、题目 问题描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小蓝有一个裁纸刀&#xff0c;每次可以将一张纸沿一条直线裁成两半。 小蓝用一张纸打印出两行三列共 6 个二维码&#xff0c;至少使用九次裁出来&#x…

    解锁数据结构分享图:高效知识传播的关键

    解锁数据结构分享图&#xff1a;高效知识传播的关键 在信息如洪流般涌来的时代&#xff0c;数据结构作为计算机科学的核心基石&#xff0c;其复杂性与重要性不言而喻。而数据结构分享图&#xff0c;则宛如一把神奇的钥匙&#xff0c;能够高效地打开理解数据结构知识宝库的大门…

    特征表示深度解析:颜色、纹理、形状与编码

    第一部分&#xff1a;颜色与纹理特征&#xff08;Part 1&#xff09; 1. 颜色特征 颜色直方图&#xff08;Color Histogram&#xff09; 定义&#xff1a;统计图像中各颜色通道&#xff08;R/G/B&#xff09;的像素分布&#xff0c;形成直方图。 计算步骤&#xff1a; 将每个…

    简单工厂 、工厂方法模式和抽象工厂模式

    简单工厂 、工厂方法模式和抽象工厂模式 1.模式性质与定位 简单工厂:并非正式的设计模式(属编程习惯),通过单一工厂类根据参数判断创建不同产品,本质是将对象创建逻辑集中管理。 工厂方法:是标准的创建型设计模式,定义抽象创建接口,由子类决定实例化哪个具体产品类,…

    多线程--参数传递之间的关系

    在C中创建线程时&#xff0c;传递参数的方式会影响参数的生命周期、线程的安全性和性能。以下是几种常见的传递方式及其适用情况&#xff1a; 1. 值传递 值传递会创建参数的副本&#xff0c;并在线程函数内部使用该副本。这种方式可以避免线程之间的竞态条件&#xff0c;因为…

    hive 中可能产生小文件的场景

    在 Hive 中&#xff0c;小文件是指文件大小远小于 HDFS 块大小&#xff08;通常为 128 MB 或 256 MB&#xff09;的文件。小文件过多会导致 NameNode 内存压力增大、查询性能下降以及资源浪费。以下是 Hive 中可能产生小文件的常见场景&#xff1a; 1. 高频插入数据 场景描述 …

    推理大模型时代,TextIn ParseX助力出版业知识资产重构

    在大语言模型&#xff08;LLM&#xff09;与推理能力快速进化的技术浪潮下&#xff0c;出版机构沉淀数十年的非结构化数据资产&#xff0c;包括书籍、期刊、手稿及历史档案&#xff0c;正在焕发新的机遇。基于文档解析、NLP与大模型的推理生成能力&#xff0c;我们在图书馆层层…

    MyBatis - XML 操作动态 SQL

    目录 1. 前言 2. 动态插入 2.1 if 标签 2.2 trim 标签 2.2.1 注解完成动态 SQL 3. 动态查询 3.1 添加 1 1 3.2 where 标签 4. 动态更新 4.1 set 标签 5. foreach 标签 6. sql 标签 & include 标签 1. 前言 之前博文所讲的 MyBatis SQL 操作, 都必须按照注解或…