【springBoot】springAOP

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";
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战

文章目录 &#xff08;提供数据集下载&#xff09;基于大语言模型LangChain与ChatGLM3-6B本地知识库调优&#xff1a;数据集优化、参数调整、提示词Prompt优化本地知识库目标操作步骤问答测试的预设问题原始数据情况数据集优化&#xff1a;预处理&#xff0c;先后准备了三份数据…

C#使用一个泛型方法操作不同数据类型的数组

目录 一、泛型方法及其存在的意义 二 、实例 1.源码 2.生成效果 再发一个泛型方法的示例。 一、泛型方法及其存在的意义 实际应用中&#xff0c;查找或遍历数组中的值时&#xff0c;有时因为数组类型的不同&#xff0c;需要对不同的数组进行操作&#xff0c;那么,可以使用…

Java学习-21 网络编程

什么是网络编程&#xff1f; 可以让设备中的程序与网络上其他设备中的程序进行数据交互&#xff08;实现网络通信的&#xff09; 基本的通信架构 基本的通信架构有2种形式: CS架构(Client客户端/Server服务端) BS架构(Browser浏览器/Server服务端)。 网络通信三要素 IP …

ATCoder Beginnner Contest 341 A~G

A.Print 341&#xff08;模拟&#xff09; 题意&#xff1a; 给定一个正整数 N N N&#xff0c;输出由 N N N个0和 ( N 1 ) (N1) (N1)个1交替组成的字符串。 分析&#xff1a; 按题意模拟即可 代码&#xff1a; #include<bits/stdc.h>using namespace std;int mai…

TestNG与ExtentReport单元测试导出报告文档

TestNG与ExtentReport集成 目录 1 通过实现ITestListener的方法添加Reporter log 1.1 MyTestListener设置 1.2 输出结果 2 TestNG与ExtentReporter集成 2.1 项目结构 2.2 MyExtentReportListener设置 2.3 单多Suite、Test组合测试 2.3.1 单Suite单Test 2.3…

十七、多线程

一、目标 理解线程的概念掌握线程的创建和启动了解线程的状态掌握线程调度的常用方法掌握线程的同步理解线程安全的类型 二、进程、线程、多线程的理解 进程&#xff1a;应用程序的执行实例、有独立的内存空间和系统资源 线程&#xff1a;CPU调度和分派的基本单位、进程中执行运…

2023数据要素市场十大关键词

2023数据要素市场十大关键词 导读 2023年即将过去。一年之前&#xff0c;《中共中央国务院关于构建数据基础制度更好发挥数据要素作用的意见》&#xff08;简称“数据二十条”&#xff09;正式对外发布&#xff0c;为数据要素市场的建设举旗定向。 图片 2023年是“数据二十条…

抖店开通后的这些基础搭建,你了解吗?今天一文详解!

大家好&#xff0c;我是电商小布。 很多小伙伴在我们店铺开通后&#xff0c;接下来就会进行选品上架等工作。 但其实&#xff0c;在店铺刚开通时&#xff0c;小店的基础设置是并不完善的。 比如说&#xff1a;平台默认店铺是全地区包邮的。 想要让小店顺利运转&#xff0c;…

徐晓艺被波兰前总统布罗尼斯瓦夫·科莫罗夫斯基接见

2024年1月19日,科莫罗夫斯基阁下总统俱乐部全球主席总统有话说共同主席波兰第五任总统布罗尼斯瓦夫科莫罗夫斯基 Former President of Poland莅临北京丰台宴 科莫罗夫斯基总统阁下一生充满传奇,他的外交成就也颇为杰出,其中一项就是中波关系。他说:“我作为总统在2011年对华访…

vue3 toRefs之后的变量修改方法

上效果 修改值需要带上解构之前的对象名obj&#xff0c; changeName:()>{ // toRefs 解决后变量修改值方法&#xff1a; 解构前变量.字段新值 obj.name FEIFEI; } } 案例源码 <!DOCTYPE html> <html> <head><me…

【Azure 架构师学习笔记】- Azure Databricks (10) -- UC 使用

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (9) – UC权限 在前面的文章&#xff1a;【Azure 架构师学习笔记】- Azure Databricks (6) - 配置Unity Catalog中演示了如何配置一个UC。 本文…

【Vuforia+Unity】AR04-地面、桌面平面识别功能

不论你是否曾有过相关经验&#xff0c;只要跟随本文的步骤&#xff0c;你就可以成功地创建你自己的AR应用。 官方教程Ground Plane in Unity | Vuforia Library 这个功能很棒&#xff0c;但是要求也很不友好&#xff0c;只能支持部分移动设备&#xff0c;具体清单如下&#xf…

书生·浦语大模型实战营第六节课作业

基础作业 python run.py --datasets ceval_gen --hf-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-kwargs padding_sideleft truncationleft trust_remote_codeTrue --m…

栽花-第15届蓝桥第4次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第169讲。 第15届蓝桥杯第4次STEMA测评已于2024年1月28日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&a…

HarmonyOS—添加/删除Module

Module是应用/服务的基本功能单元&#xff0c;包含了源代码、资源文件、第三方库及应用/服务配置文件&#xff0c;每一个Module都可以独立进行编译和运行。一个HarmonyOS应用/服务通常会包含一个或多个Module&#xff0c;因此&#xff0c;可以在工程中创建多个Module&#xff0…

什么是web组态?

一、web组态的定义和背景 在深入探讨之前&#xff0c;我们先回顾一下“组态”的定义。在工业自动化领域&#xff0c;组态软件是用于创建监控和数据采集&#xff08;SCADA&#xff09;系统的工具&#xff0c;它允许工程师构建图形界面&#xff0c;实现与各种设备和机器的数据交互…

性能全面提升!探索ONLYOFFICE最新8.0版:更快速、更强大,PDF表单编辑轻松搞定!

文章目录 PDF表单功能表单模板 屏幕朗读器功能EXCEL新增功能单变量求解图表向导数字排序 PPT 新增功能新增语言区域设置和优化插件界面 ONLYOFFICE 是由 Ascensio System SIA 推出的一款功能强大的办公套件&#xff0c;其中提供了适用于文本文档、表格以及演示文稿的在线编辑软…

通过盲注脚本复习sqllabs第46关order by 注入

在MySQL支持使用ORDER BY语句对查询结果集进行排序处理&#xff0c;使用ORDER BY语句不仅支持对单列数据的排序&#xff0c;还支持对数据表中多列数据的排序。语法格式如下 select * from 表名 order by 列名(或者数字) asc&#xff1b;升序(默认升序) select * from 表名 or…

win10系统secoclient连接服务器时,报错与对方建立连接超时,配置错误或网络故障

故障原因 secoclient连接时出现超时的故障&#xff0c;之前还是正常的&#xff0c;可能与最近的系统更新有关 解决方案 找到设备管理 找到网络适配器下的SVN adapter V1.0 禁用该适配器 进入C:\Windows\System32\drivers 找到SVNDrv.sys 把这个文件删除或者重命名一下…

解决docker中运行的jar包连不上前端程序

目录 检查端口映射 查看容器的 IP 地址 检查容器网络设置 防火墙和网络策略 前端程序配置 跨域资源共享 (CORS) 日志查看 连接问题通常涉及到网络配置和端口映射。确保你在 Docker 中运行的 JAR 包可以被前端程序访问&#xff0c;可以采取以下步骤来解决问题&#xff1a…