【Spring Boot】Spring AOP 快速上手指南:开启面向切面编程新旅程

news2025/7/14 5:51:26

前言

🌟🌟本期讲解关于spring aop的入门介绍~~~

🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客

🔥 你的点赞就是小编不断更新的最大动力                                       

🎆那么废话不多说直接开整吧~~

 

目录

📚️1.AOP概述

1.1什么是AOP

 1.2什么是Spring AOP

📚️2.Spring AOP入门

2.1环境设置

2.2代码编写

📚️3.Spring AOP详细

3.1Spring AOP核心概念

1.切点

2.连接点

3.通知

4.切面

3.2Spring AOP通知类型

3.3@pointcut注解

3.4@order切面优先级

📚️4.总结

 

📚️1.AOP概述

1.1什么是AOP

AOP是Spring框架的第⼆⼤核⼼(第⼀⼤核⼼是IoC),说明AOP也是非常重要的;

AOP:Aspect Oriented Programming(⾯向切⾯编程)

面向切面编程:所谓的这里的切面就是表示一类特殊的问题,所以也叫面向特定方法编程;

这里特定的方法,在之前学习过的spring统一功能处理中,涉及到登录校验问题,而拦截器就是对这类问题的统一求解,AOP是一种求解问题的思想,那么拦截器就是一种思想的实现;

总结:

简单来说: AOP是⼀种思想, 是对某⼀类事情的集中处理

 1.2什么是Spring AOP

 AOP是⼀种思想, 它的实现⽅法有很多, 有Spring AOP,也有AspectJ、CGLIB等.Spring AOP是其中的⼀种实现⽅式;

在日常的代码编写中,有以下列子:

假如,我们要对这里面的接口实现改良,让执行时间减少,这里就定位到某些业务代码逻辑等改进,但是不是所有都是不好的,所以我们需要进行测试每个接口,业务执行的时间,那么就有如下的代码,来进行时间检测:

此时的方法固然是可以的,但是那么多接口都需要这样写吗??答案是不可能的,此时这就是一类特定的问题,此时我们就可以使用AOP思想来进行解决~~~

AOP就可以做到在不改动这些原始⽅法的基础上, 针对特定的⽅法进⾏功能的增强.
AOP的作⽤:在程序运⾏期间在不修改源代码的基础上对已有⽅法进⾏增强(⽆侵⼊性: 解耦)

📚️2.Spring AOP入门

2.1环境设置

首先创建一个springboot项目,设置Maven,然后引入如下的依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

 这里还可以引入lombok来进行slf4j日志打印,但是在新版本中要将引入的lombok中一部分给注释掉,如下所示:

           <plugins>
           <!-- <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>-->
            <plugin>

2.2代码编写

具体的代码如下所示:

@Slf4j
@Aspect
@Component
//交给spring进行管理
public class TimeAspect {

    @Around("execution(* com.example.springaop.controller.*.*(..))")
    public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {
        //记录开始时间
        long start = System.currentTimeMillis();
        //执行目标方法
        Object proceed = joinPoint.proceed();
        //记录结束时间
        long end = System.currentTimeMillis();
        //日志打印耗时
        log.info("耗时时间: "+ (end-start) + "ms");
        return proceed;
    }
}

解释:

1. @Aspect: 标识这是⼀个切⾯类
2. @Around: 环绕通知, 在⽬标⽅法的前后都会被执⾏. 后⾯的表达式表⽰对哪些⽅法进⾏增强.
3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏

那么上述代码大致分为如下:

总结优势:

• 代码⽆侵⼊: 不修改原始的业务⽅法, 就可以对原始的业务⽅法进⾏了功能的增强或者是功能的改变
• 减少了重复代码
• 提⾼开发效率
• 维护⽅便 

📚️3.Spring AOP详细

3.1Spring AOP核心概念

1.切点

切点(Pointcut), 也称之为"切⼊点"
Pointcut 的作⽤就是提供⼀组规则 (使⽤ AspectJ pointcut expression language 来描述), 告诉程序对哪些⽅法来进⾏功能增强

如下所示:

execution(* com.example.springaop.controller.*.*(..))

这个就是切点表达式;

2.连接点

满⾜切点表达式规则的⽅法, 就是连接点. 也就是可以被AOP控制的⽅法,上述切点表达式中的类就是controller,说明这里面的所有方法都是AOP控制方法;

解释:直白来说就是我们需要操作的解决的一类问题接口,就是受到AOP管理的; 

这个就是连接点;

3.通知

通知就是具体要做的⼯作, 指哪些重复的逻辑,也就是共性功能(最终体现为⼀个⽅法)⽐如上述程序中记录业务⽅法的耗时时间, 就是通知;

具体的部分就是如下:

在AOP⾯向切⾯编程当中, 我们把这部分重复的代码逻辑抽取出来单独定义, 这部分代码就是通知的内容. 

4.切面

切⾯(Aspect) = 切点(Pointcut) + 通知(Advice)
通过切⾯就能够描述当前AOP程序需要针对于哪些⽅法, 在什么时候执⾏什么样的操作,切面包含了通知中要执行的逻辑,以及连接点的定义

3.2Spring AOP通知类型

Spring中AOP的通知类型有以下⼏种:
• @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
• @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
• @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
• @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执⾏
• @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏

那么这里主要是通过代码来进行实验;

每个通知类型的代码如下所示:

@Slf4j
@Component
@Aspect
public class AspectDemo1 {
    
    @Around("execution(* com.example.springaop.controller.*.*(..))")
    public Object aroundTest(ProceedingJoinPoint point) throws Throwable {
        //通知
        log.info("Around 开始执行");
        //执行目标函数
        Object result = point.proceed();
        //结束打印
        log.info("Around 结束执行");
        return result;
    }

    @Before("execution(* com.example.springaop.controller.*.*(..))")
    public void beforeTest(){
        log.info("before 开始执行");
    }

    @After("execution(* com.example.springaop.controller.*.*(..))")
    public void afterTest(){
        log.info("after 开始执行");
    }

    @AfterReturning("execution(* com.example.springaop.controller.*.*(..))")
    public void afterReturnTest(){
        log.info("afterReturn 开始执行");
    }

    @AfterThrowing("execution(* com.example.springaop.controller.*.*(..))")
    public void afterThrowTest(){
        log.info("afterThrow 开始执行");
    }
}

解释:

从上到下依次的通知类型,就是注解所表示,但是对于环绕通知中,要包含这里的连接点,即目标执行方法,以及返回类型是object;环绕通知需要调⽤ ProceedingJoinPoint.proceed() 来让原始⽅法执⾏, 其他通知不需要考虑⽬标⽅法执⾏;

此时运行如下的测试类:

@Slf4j
@RestController
@RequestMapping("/test")
public class AspectTest {
    @RequestMapping("/t1")
    public String test1(){
        log.info("这是目标方法,开始执行");
        return "t1";
    }
   @RequestMapping("/t2")
    public String test2(){
        log.info("这是目标方法,开始执行");
        int a=10/0;
        return "t2";
    }
}

那么此时我们先运行这里没有算数异常的代码,输出的情况如下所示:

解释:

程序正常运⾏的情况下, @AfterThrowing 标识的通知⽅法不会执⾏
从上图也可以看出来, @Around 标识的通知⽅法包含两部分, ⼀个"前置逻辑", ⼀个"后置逻辑".其
中"前置逻辑" 会先于 @Before 标识的通知⽅法执⾏, "后置逻辑" 会晚于 @After 标识的通知⽅法执
⾏ 

此时运行异常代码,结果如下所示:

解释:

@AfterReturning 标识的通知⽅法不会执⾏, @AfterThrowing 标识的通知⽅法执⾏了
• @Around 环绕通知中原始⽅法调⽤时有异常,通知中的环绕后的代码逻辑也不会在执⾏了(因为
原始⽅法调⽤出异常了

3.3@pointcut注解

上⾯代码存在⼀个问题, 就是存在⼤量重复的切点表达式 execution(* com.example.demo.controller.*.*(..)) , Spring提供了 @PointCut 注解, 把公共的切点
表达式提取出来, 需要⽤到时引⽤该切⼊点表达式即可

代码如下所示:

 @Pointcut("execution(* com.example.springaop.controller.*.*(..))")
     public void pt(){}

    @Around("pt()")
    public Object aroundTest(ProceedingJoinPoint point) throws Throwable {
        //通知
        log.info("Around 开始执行");
        //执行目标函数
        Object result = point.proceed();
        //结束打印
        log.info("Around 结束执行");
        return result;
    }

解释:

此时就是通过@pointcut注解,对于切点表达式进行了提取,那么之后再次进行通知注解的切点表达式编写时,就可以直接使用提取的方法;

这里的方法若设置为私有类,那么只能在这一个类中进行使用,但是如果其他类要使用,这里必须变成public访问限定符

代码如下所示:

@Slf4j
@Aspect
public class AspectDemo2 {
    @Before("com.example.springaop.aspect.AspectDemo1.pt()")
    public void beforeTest() {
        log.info("AspectDemo2 before 开始执行...");
    }

其中@before注解中的切点编写就是,提取方法的全限定路径+类名+方法名;

3.4@order切面优先级

假如定义了多个切⾯类时, 并且这些切⾯类的多个切⼊点都匹配到了同⼀个⽬标⽅法.情况如下所示

首先定义三个切面类,里面的通知方法大致如下:

public class AspectDemo3 {
    @Before("com.example.springaop.aspect.AspectDemo1.pt()")
    public void doBefore(){
        log.info("AspectDemo3 do before...");
    }

    @After("com.example.springaop.aspect.AspectDemo1.pt()")
    public void doAfter(){
        log.info("AspectDemo3 do after...");
    }

}

此时进行路由访问后,打印的日志如下所示:

 解释:

存在多个切⾯类时, 默认按照切⾯类的类名字⺟排序
• @Before 通知:字⺟排名靠前的先执⾏
• @After 通知:字⺟排名靠前的后执⾏ 

那么此时我们可以通过@order注解实现顺序的逆转,代码如下所示:

@Component
@Aspect
@Order(3)
public class AspectDemo3 {
}

解释:

我们设置 AspectDemo3order为3,AspectDemo4的order为2,AspectDemo5的order为1,输出的结果如下所示:

通过上述程序的运⾏结果, 得出结论:
@Order 注解标识的切⾯类, 执⾏顺序如下:
• @Before 通知:数字越⼩先执⾏
• @After 通知:数字越⼤先执⾏
@Order 控制切⾯的优先级, 先执⾏优先级较⾼的切⾯, 再执⾏优先级较低的切⾯, 最终执⾏⽬标⽅法 

📚️4.总结

本期主要讲解了关于Spring AOP入门概念,以及快速入门,以及Spring AOP的代码的详细介绍:切点,连接点,通知,以及切面的概念,还有通知类型等其他注解的介绍~~~

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

       😊😊  期待你的关注~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2273947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源CMS建站系统的安全优势有哪些?

近年来&#xff0c;用户们用开源CMS系统搭建网站的比例也越来越高&#xff0c;它为用户提供了便捷的网站建设解决方案。其中&#xff0c;亿坊CMS建站系统更因安全方面备受用户欢迎&#xff0c;下面带大家一起全面地了解一下。 一、什么是开源CMS&#xff1f; 开源CMS指的是那…

基于单片机的客车载客状况自动检测系统(论文+源码)

1系统整体设计 本课题为客车载客状况自动检测系统&#xff0c;在此以STM32单片机为核心控制器&#xff0c;结合压力传感器、红外传感器、蜂鸣器、语音提示模块、继电器、液晶等构成整个客车载客状况自动检测系统&#xff0c;整个系统架构如图2.1所示&#xff0c;在此通过两个红…

CDP集成Hudi实战-Hive

[〇]关于本文 本文测试一下使用Hive和Hudi的集成 软件版本Hudi1.0.0Hadoop Version3.1.1.7.3.1.0-197Hive Version3.1.3000.7.3.1.0-197Spark Version3.4.1.7.3.1.0-197CDP7.3.1 [一]部署Jar包 1-部署hudi-hive-sync-bundle-1.0.0.jar文件 [rootcdp73-1 ~]# for i in $(se…

网络安全 基础入门-概念名词

域名相关 域名 域名和IP地址相互映射&#xff0c;这样不用去记住能够被机器直接读取的IP地址数串 域名系统(DNS) 它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。DNS使用UDP端口53。 1. 如果是自动获取dns,就向上查询&#xff…

Rust语言使用iced实现简单GUI页面

使用cargo新建一个rust项目 cargo new gui_demo cd gui_demo 编辑Cargo.toml文件 ,添加iced依赖 [package] name "gui_demo" version "0.1.0" edition "2021"[dependencies] iced "0.4.2" 编辑src/main.rs文件&#xff1a; u…

深度学习领域创新黑马!频域特征融合新突破

最近&#xff0c;FreqFusion引起了广泛关注&#xff0c;这是一种创新的频率感知特征融合方法&#xff0c;可以提升数据处理的准确性和效率&#xff0c;尤其在语义分割、目标检测、实例分割和全景分割等任务中表现卓越。 通过结合频域分析与特征融合技术&#xff0c;FreqFusion…

毕业项目推荐:基于yolov8/yolov5的草莓病害检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

鸿蒙开发(29)弹性布局 (Flex)

概述 弹性布局&#xff08;Flex&#xff09;提供更加有效的方式对容器中的子元素进行排列、对齐和分配剩余空间。常用于页面头部导航栏的均匀分布、页面框架的搭建、多行数据的排列等。 容器默认存在主轴与交叉轴&#xff0c;子元素默认沿主轴排列&#xff0c;子元素在主轴方…

“深入浅出”系列之C++:(3)网络编程

通过网络编程实现基于网络的应用程序&#xff0c;实现计算机之间的通信和数据交换。 套接字(Socket)&#xff1a;套接字是网络编程中用于通信的一种抽象概念。在C中使用<sys/socket.h>头文件中定义的套接字函数来创建和操作套接字。目的是开发采用套接字通信的C/S网络应用…

高等数学学习笔记 ☞ 一元函数微分的基础知识

1. 微分的定义 &#xff08;1&#xff09;定义&#xff1a;设函数在点的某领域内有定义&#xff0c;取附近的点&#xff0c;对应的函数值分别为和&#xff0c; 令&#xff0c;若可以表示成&#xff0c;则称函数在点是可微的。 【 若函数在点是可微的&#xff0c;则可以表达为】…

家用万兆网络实践:紧凑型家用服务器静音化改造(二)

大家好&#xff0c;这篇文章我们继续分享家里网络设备的万兆升级和静音改造经验&#xff0c;希望对有类似需求的朋友有所帮助。 写在前面 在上一篇《家用网络升级实践&#xff1a;低成本实现局部万兆&#xff08;一&#xff09;》中&#xff0c;我们留下了一些待解决的问题。…

[控制理论]—带死区的PID控制算法及仿真

带死区的PID控制算法及仿真 1.基本概念 在计算机控制系统重&#xff0c;某些系统为了避免控制作用过于频繁&#xff0c;消除由于频繁动作所引起的振荡&#xff0c;可采用带死区的PID控制算法&#xff1a; err(k) 为位置跟踪偏差&#xff0c;err0为可调参数&#xff0c;其具体…

(概率论)无偏估计

参考文章&#xff1a;(15 封私信 / 51 条消息) 什么是无偏估计&#xff1f; - 知乎 (zhihu.com) 首先&#xff0c;第一个回答中&#xff0c;马同学图解数学讲解得很形象&#xff0c; 我的概括是&#xff1a;“注意&#xff0c;有一个总体的均值u。然后&#xff0c;如果抽样n个&…

Visio 画阀门 符号 : 电动阀的画法

本篇文章介绍阀门&#xff0c;很多朋友在利用Visio绘画管道流程简图时&#xff0c;需要进行阀门符号的绘画&#xff0c;而Visio提供的阀门符号种类并不是很齐全。 本篇文章给出电动阀的画法&#xff1a; 下图是液动阀的符号&#xff1a; 首先&#xff0c;找到“更多形状”中的…

css出现边框

前言 正常情况下&#xff0c;开启 contenteditable 属性后会出现 “黑色边框”。 如下图所示&#xff0c;很影响美观&#xff1a; 您可能想去掉它&#xff0c;就像下面这样&#xff1a; 解决方案 通过选择器&#xff0c;将 focus 聚焦时移除 outline 属性即可。 如下代码所示&a…

【HarmonyOS NEXT】鸿蒙应用使用后台任务之长时任务,解决屏幕录制音乐播放等操作不被挂起

【HarmonyOS NEXT】鸿蒙应用使用后台任务之长时任务&#xff0c;解决屏幕录制音乐播放等操作不被挂起 一、前言 1.后台是什么&#xff1f; 了解后台任务和长时任务前&#xff0c;我们需要先明白鸿蒙的后台特性&#xff1a;所谓的后台&#xff0c;指的是设备返回主界面、锁屏、…

【JVM】总结篇之垃圾回收★

文章目录 为什么需要GC垃圾回收算法★垃圾判断阶段引用计数算法可达性分析GC roots为什么会stop world?垃圾清除阶段标记-清除(Mark - Sweep)算法复制(Copying)算法标记-压缩(或标记-整理、Mark - Compact)算法分代收集算法增量收集(Incremental Collecting)算法分区算…

【Redis源码】 RedisObject结构体

【Redis源码】 RedisObject结构体 文章目录 【Redis源码】 RedisObject结构体概要1. redis object 由来2. 通过汇编代码分析3. 总结 概要 博主这里从redis object由来&#xff0c;和从底层内存分配角度进行讲解哦&#xff0c;小伙伴们自行选择读取 1. redis object 由来 ​ …

Ungoogled Chromium127 编译指南 MacOS 篇(二)- 项目要求

1. 引言 在开始编译 Ungoogled Chromium 之前&#xff0c;我们需要确保系统满足所有必要的硬件和软件要求。由于浏览器编译是一个资源密集型的任务&#xff0c;合适的硬件配置和完整的软件环境至关重要。本文将详细介绍编译 Ungoogled Chromium 所需的各项要求。 2. 硬件要求…

专家混合(MoE)大语言模型:免费的嵌入模型新宠

专家混合&#xff08;MoE&#xff09;大语言模型&#xff1a;免费的嵌入模型新宠 今天&#xff0c;我们深入探讨一种备受瞩目的架构——专家混合&#xff08;Mixture-of-Experts&#xff0c;MoE&#xff09;大语言模型&#xff0c;它在嵌入模型领域展现出了独特的魅力。 一、M…