【springBoot】springAOP

news2025/7/21 22:15:05

AOP的概述

AOP是面向切面编程。切面就是指某一类特定的问题,所以AOP也可以理解为面向特定方法编程。AOP是一种思想,拦截器,统一数据返回和统一异常处理是AOP思想的一种实现。简单来说:AOP是一种思想,对某一类事务的集中处理。

spring对AOP进行了实现,并且提供了一些API,这就是spring AOP.

spring AOP的简单使用

预先准备:

@RestController
public class TestController {
    @RequestMapping("/t1")
    public String t1(){
        String sum = "";
        for (int i = 1; i <= 10000; i++) {
            sum += 'a';
        }
        return "t1";
    }

    @RequestMapping("/t2")
    public String t2(){
        StringBuilder sum = new StringBuilder();
        for (int i = 1; i <= 10000; i++) {
            sum.append('a');
        }
        return "t2";
    }
}
  1. 引入springAOP依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 编写AOP程序
@Slf4j
@Aspect//表示是一个切面类
@Component
public class TimeAspect {
    @Around("execution(* com.example.aopdemo.controller.*.*(..))")//作用域
    public Object timeCost(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();//方法执行前的逻辑
        Object result = joinPoint.proceed();//执行目标方法
        long end = System.currentTimeMillis();//方法执行后的逻辑
        log.info(joinPoint + "消耗时间:" + (end - start) + "ms");
        return result;
    }
}

我们通过AOP⼊⻔程序完成了业务接⼝执⾏耗时的统计.

@Around:环绕通知,在⽬标⽅法的前后都会被执⾏.后⾯的表达式表⽰对哪些⽅法进⾏增强

优点:

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

spring AOP 详解

spring AOP 的核心概念(了解)

  1. 切点:一组规则,通过表达式来描述
  2. 连接点: 切面要作用的方法,目标方法切点描述的方法.
  3. 通知:具体的逻辑,要做什么事情
  4. 切面:切点+通知

image-20240201200843227

com.example.aopdemo.controller目录下的方法就是连接点。

切点和连接点的关系:连接点是满⾜切点表达式的元素.切点可以看做是保存了众多连接点的⼀个集合.

spring AOP通知类型

  • @Around:环绕通知,此注解标注的通知方法在目标方法前,后都被执行 --> 使用最多
  • @Before:前置通知,此注解标注的通知方法在目标方法前被执行
  • @After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  • @AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  • @AfterThrowing:异常后通知,此注解标注的通知方法发⽣异常后执行
@Slf4j
@Aspect
@Component
public class AspectDemo {
    //定义切点
    @Pointcut("execution(* com.example.aopdemo.controller.*.*(..))")
    public void pt(){
    }
    @Before("pt()")//后置通知
    public void doBefore(){
        log.info("执行AspectDemo doBefore……");
    }
    @After("pt()")//前置通知
    public void doAfter(){
        log.info("执行AspectDemo doAfter……");
    }
    @AfterReturning("pt()")//返回后通知
    public void doAfterReturning(){
        log.info("执行AspectDemo doAfterReturning……");
    }
    @AfterThrowing("pt()")//异常后通知
    public void doAfterThrowing(){
        log.info("执行AspectDemo doAfterThrowing……");
    }
    @SneakyThrows
    @Around("pt()")//环绕通知
    public Object doAround(ProceedingJoinPoint joinPoint){
        log.info("执行AspectDemo doAround前……");
        Object result = joinPoint.proceed();
        log.info("执行AspectDemo doAround后……");
        return result;
    }
}

正常执行结果:

先执行around,再执行before。先执行after,再执行Around。

image-20240201204352259

异常执行结果:

当发生异常时,不执行AfterReturning,也不执行Around的方法后的逻辑

image-20240201204522479

@PointCut,定义切点

如果其他类需要使用,需要把切点声明为public.使用时,类的全限定名称+切点名称 ==> 包+类名

@Slf4j
@Aspect
@Component
public class AspectDemo1 {
    @After("com.example.aopdemo.aspect.AspectDemo.pt()")//前置通知
    public void doAfter(){
        log.info("执行AspectDemo1 doAfter……");
    }
}

切面的优先级

定义三个切面类:

@Slf4j
@Aspect
@Component
public class AspectDemo1 {
    @Before("com.example.aopdemo.aspect.AspectDemo.pt()")//后置通知
    public void doBefore(){
        log.info("执行AspectDemo1 doBefore……");
    }
    @After("com.example.aopdemo.aspect.AspectDemo.pt()")//前置通知
    public void doAfter(){
        log.info("执行AspectDemo1 doAfter……");
    }
}
@Slf4j
@Aspect
@Component
public class AspectDemo2 {
    @Before("com.example.aopdemo.aspect.AspectDemo.pt()")//后置通知
    public void doBefore(){
        log.info("执行AspectDemo2 doBefore……");
    }
    @After("com.example.aopdemo.aspect.AspectDemo.pt()")//前置通知
    public void doAfter(){
        log.info("执行AspectDemo2 doAfter……");
    }
}
@Slf4j
@Aspect
@Component
public class AspectDemo3 {
    @Before("com.example.aopdemo.aspect.AspectDemo.pt()")//后置通知
    public void doBefore(){
        log.info("执行AspectDemo3 doBefore……");
    }
    @After("com.example.aopdemo.aspect.AspectDemo.pt()")//前置通知
    public void doAfter(){
        log.info("执行AspectDemo3 doAfter……");
    }
}

存在多个切面类时,默认按照切面类的类名字母排序:

  • @Before通知:字母排名靠前的先执行
  • @After通知:字母排名靠前的后执行

image-20240201211100129

优先级高:先执行before,后执行After

Spring给我们提供了一个新的注解,来控制这些切面通知的执行顺序:@Order。使用@Order时,数字越小,优先级越高

@Order(2)
public class AspectDemo1 {
}
@Order(3)
public class AspectDemo2 {
}
@Order(1)
public class AspectDemo3 {
}

执行结果:

image-20240201211631225

@Order控制切面的优先级,先执行优先级较高的切面,再执行优先级较低的切面,最终执行目标方法.

image-20240201211754075

切点表达式

切点表达式常见有两种表达方式

  1. execution(…):根据方法的签名来匹配
  2. @annotation(…):根据注解匹配

execution表达式上面已经用过.

主要介绍切点表达式支持通配符表达:

    • :匹配任意字符,只匹配一个元素(返回类型,包,类名,方法或者方法去参数
    • 包名使用 * 表示任意包(一层包使用一个*)
    • 类名使用 * 表示任意类
    • 返回值使用 *表示任意返回值类型
    • 方法名使用 * 表示任意方法
    • 参数使用 * 表示一个任意类型的参数
  1. … :匹配多个连续的任意符号,可以通配任意层级的包,或任意类型,任意个数的参数

    • 使用 … 配置包名,标识此包以及此包下的所有子包
    • 可以使用 … 配置参数,任意个任意类型的参数

execution表达式更适用有规则的,如果我们要匹配多个无规则的方法,比如:TestController中的t1和UserController中的u1()这两个方法。这个时候我们使用execution这种切点表达式来描述就不是是很方便了。我们可以借助自定义注解的方式以及另一种切点表达式@annotation来描述这一类的切点。

实现步骤:

  1. 编写自定义注解
  2. 使用@annotation表达式来描述切点
  3. 在连接点的方法上添加自定义注解

准备测试代码:

@RestController
public class UserController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
    @RequestMapping("/h1")
    public String h1(){
        return "h1";
    }
    @RequestMapping("/h2")
    public String h2(){
        return "h2";
    }
}

编写自定义注解:

@Target({ElementType.METHOD})//标识了 Annotation所修饰的对象范围,即该注解可以用在什么地方(方法上)
@Retention(RetentionPolicy.RUNTIME)//指Annotation被保留的时间长短,标明注解的生命周期(运行时注解)
public @interface MyAspect {
}

使用@annotation表达式来描述切点

@Slf4j
@Component
@Aspect
public class MyAspectDemo {
    @Before("@annotation(com.example.aopdemo.aspect.MyAspect)")
    public void doBefore(){
        log.info("执行MyAspectDemo before...");
    }
    @After("@annotation(com.example.aopdemo.aspect.MyAspect)")
    public void doAfter1(){
        log.info("执行MyAspectDemo doAfter...");
    }
	//所有使用RequestMapping注解都会触发
    @After("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void doAfter(){
        log.info("执行RequestMapping doAfter...");
    }
}

在连接点的方法上添加自定义注解:

@MyAspect    
@RequestMapping("/h1")
public String h1(){
    return "h1";
}

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

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

相关文章

B端系统:工作台页面,如何从平庸走向出众

Hi&#xff0c;大家好&#xff0c;我是贝格前端工场&#xff0c;从事8年前端开发的老司机。大家看过很多平庸的工作台页面&#xff0c;但是仔细分析过平庸的表现吗&#xff0c;仔细思考过如何实现出众的效果吗&#xff1f;这篇文章为你解读。 一、工作台页面是什么&#xff0c;…

深信服技术认证“SCCA-C”划重点:深信服超融合HCI

为帮助大家更加系统化地学习云计算知识&#xff0c;高效通过云计算工程师认证&#xff0c;深信服特推出“SCCA-C认证备考秘笈”&#xff0c;共十期内容。“考试重点”内容框架&#xff0c;帮助大家快速get重点知识 划重点来啦 *点击图片放大展示 深信服云计算认证&#xff08;S…

【STC8A8K64D4开发板】第2-13讲:SPI总线的应用

第2-13讲&#xff1a;SPI总线的应用 学习目的了解SPI总线的结构、特点以及4种通信模式。掌握通过SPI读、写和擦除SPI Flash W25Q128的方法以及代码编写。掌握通过SPI读、写铁电存储器FM25CL64B的方法以及代码编写。 SPI总线原理 SPI是串行外设接口(Serial Peripheral Interfa…

AI 视频 | Stable Video 开放公测了,免部署,免费使用!谁说 4 秒的 AI 视频不香?!

谁说 4 秒的视频不香&#xff1f;2.21 日&#xff0c;Stable Video 开放公测了&#xff0c;不需要自己部署了&#xff0c;直接在网页上就可以生成视频了。 下面这些视频&#xff0c;都是通过 Stable Video Diffusion 生成的&#xff0c;可以先来感受一下&#xff1a; Stable V…

JavaScript的内存管理与垃圾回收

前言 JavaScript提供了高效的内存管理机制&#xff0c;它的垃圾回收功能是自动的。在我们创建新对象、函数、原始类型和变量时&#xff0c;所有这些编程元素都会占用内存。那么JavaScript是如何管理这些元素并在它们不再使用时清理它们的呢&#xff1f; 在本节中&#xff0c;…

LED景观照明灯驱动电路串联、并联和恒流3款方案

LED景观照明灯是现代城市照明中常见的一种灯具。为了保证LED景观照明灯的正常工作&#xff0c;需要设计合适的驱动电路。LED景观照明灯的驱动电路可以采用串联、并联或恒流的方式来设计。 首先&#xff0c;串联驱动电路是指将多个LED灯串联在一起&#xff0c;然后接入电源进行…

不做内容引流,你凭什么在互联网上赚钱?

孩子们放寒假了&#xff0c;待在家里不是看电视&#xff0c;就是拿着手机刷视频&#xff0c;脸上是各种欢快和满足。只是一切换到写作业模式&#xff0c;孩子是各种痛苦表情包&#xff0c;家长则是使出浑身解数&#xff0c;上演亲子大战。可见娱乐常常让人愉悦&#xff0c;而学…

MyBatis-Plus框架(千峰学习笔记)

简介 MyBatis-Plus是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;主要作用 为简化开发、提高效率。 我们的愿景是成为 MyBatis 最好的搭档&#xff0c;就像 魂斗罗 中的 1P、2P&#xff0c;基友搭配&#xff0c;效率翻倍。 特性 ● …

XFF伪造 [MRCTF2020]PYWebsite1

打开题目 直接查看源码 看到一个./flag.php 访问一下 购买者的ip已经被记录&#xff0c;本地可以看到flag&#xff0c;那么使用xff或者client-ip伪造一下ip试试 bp抓包 加一个X-Forwarded-For头 得到flag

无线局域网(WLAN)简单概述

无线局域网 无线局域网概述 无限局域网&#xff08;Wireless Local Area Network&#xff0c;WLAN&#xff09;是一种短距离无线通信组网技术&#xff0c;它是以无线信道为传输媒质构成的计算机网络&#xff0c;通过无线电传播技术来实现在空间传输数据。 WLAN是传输范围在1…

2、Web攻防-SQL注入-联合查询注入

用途&#xff1a;个人学习笔记&#xff0c;有所借鉴&#xff0c;欢迎指正&#xff01; 声明&#xff1a;只用于学习交流&#xff0c;点到为止&#xff0c;请勿非法测试。 概念&#xff1a; 联合查询注入&#xff1a;联合注入是回显注入的一种&#xff0c;也就是说联合注入的前…

关于Android下gralloc,hwcompoer以及surface模块的重新认识

关于Android下gralloc&#xff0c;hwcompoer以及surface模块的重新认识 引言 欠债还钱天经地义&#xff0c;知识的债也是如此&#xff01;这不必须得将我前面欠下来的债给补上&#xff01;对于任何复杂的知识点&#xff0c;我们都可以采用庖丁解牛的学习方式&#xff0c;一步步…

DSL Query基本语法

DSL Query基本语法 查询的基本语法如下&#xff1a; GET /indexName/_search {"query":{"查询类型":{"查询条件":"条件值"}} }查询所有 GET /indexName/_search {"query":{"match_all":{}} }match查询&#xf…

5分钟让你搞懂什么是Http协议

计算机网络基础课程是计算机专业方向非常重要的一门功课。 所有的互联网都通过网络协议来建立通信连接。 而http协议又是一种无状态的协议&#xff0c;也是工作中最常用的一种基于Web浏览器的网络通信协议。 如何学习http协议&#xff1f;提供三种方法供参考&#xff1a; 第…

分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测

分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测 目录 分类预测 | Matlab实现KPCA-ISSA-LSSVM基于核主成分分析和改进的麻雀搜索算法优化最小二乘支持向量机故障诊断分类预测分类效果基本描述程序设计参考资…

4.网络游戏逆向分析与漏洞攻防-游戏启动流程漏洞-模拟游戏登陆器启动游戏并且完成注入

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;游戏启动流程的分析 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;bcf7559184863febdcad819e48aaacad9f25d633 代码下…

第三百六十二回

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"如何创建垂直方向的Switch"相关的内容&#xff0c;本章回中将介绍SlideSwitch组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

在ubuntu20.04 上配置 qemu/kvm linux kernel调试环境

一&#xff1a;安装qemu/kvm 和 virsh qemu/kvm 是虚拟机软件&#xff0c;virsh是管理虚拟机的命令行工具&#xff0c;可以使用virsh创建&#xff0c;编辑&#xff0c;启动&#xff0c;停止&#xff0c;删除虚拟机。 &#xff08;1&#xff09;&#xff1a;安装之前&#xff0c…

九州金榜|家庭教育小技巧,孩子好习惯养成记

家庭教育对于孩子的发展至关重要&#xff0c;家长一定要重视孩子在家里的举动&#xff0c;要及时纠正孩子的不足&#xff0c;发展孩子的优良品德和教孩子养成勤俭朴素的的好习惯。九州金榜家庭教育将从以下方面说一下家庭教育中的方法技巧。 一、家长以身作则 家长教育孩子&a…

js设计模式:策略模式

作用: 根据不同的条件去进行相应的业务逻辑处理 就好比针对每种情况都制定对应的方案,触发条件就启动某项方案策略 示例: //策略对象const arrangeFun {model1:(value1,value2,value3,value4)>{return ${value1}${value2}${value3}:${value4}},model2:(value1,value2,va…