详解 Springboot 中使用 Aop

2023-10-26

一、什么是 Aop

AOP (Aspect Oriented Programming),意为面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

AOP的编程思想是把对类对象的横切问题点,从业务逻辑中分离出来,从而达到解耦的目的,增加代码的复用性,提高开发效率。

没使用Aop之前的:
在这里插入图片描述
使用Aop之后:
在这里插入图片描述

AOP的应用场景:
在这里插入图片描述

二、 使用到的相关注解

@Component 将当前类注入到Spring容器内

@Aspect :表明是一个切面类

@Before :前置通知,在方法执行之前执行

@After :后置通知,在方法执行之后执行

@AfterRuturning :返回通知,在方法返回结果之后执行

@AfterThrowing :异常通知,在方法抛出异常之后执行

@Around :环绕通知,围绕着方法执行

@Pointcut :切入点,PointCut(切入点)表达式有很多种,其中execution用于使用切面的连接点。

注意:上面所提到的五种通知方法中,除了环绕通知外,其他的四个通知注解中,加或者不加参数JoinPoint都可以,如果有用到JoinPoint的地方就加,用不到就可以不加。

在这里插入图片描述

三、 Aop 相关概念

Joinpoint(连接点):所谓连接点是指那些被拦截到的点,在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点,通俗的说就是被增强类中的所有方法

PointCut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义,通俗的说就是被增强类中的被增强的方法,因为被增强类中并不是所有的方法都被代理了

Advice(通知/增强):所谓通知是指拦截到 Joinpoint (被增强的方法)之后所要做的事情就是通知,通俗的说就是对被增强的方法进行增强的代码

通知的类型:前置通知,返回通知,异常通知,后置通知,环绕通知

前置通知:在被代理方法执行之前执行

返回通知:在被代理方法执行之后执行

异常通知:在被代理方法执行出错的时候执行

后置通知:无论怎样都会执行

注意:返回通知和异常通知只能有一个会被执行,因为发生异常执行异常通知,然后就不会继续向下执行,自然后置通知也就不会被执行,反之亦然。

Aspect(切面):是切入点和通知(引介)的结合,通俗的说就是建立切入点和通知方法在创建时的对应关系

四、@PointCut 表达式详解

PointCut:切入点,指哪些方法需要被执行AOP,PointCut表达式可以有一下几种方式

1、execution(表达式)

表达式:访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)

标准的表达式写法范例:

public void com.aismall.testaop.controller.HelloController.helloAop()

访问修饰符可以省略

void com.aismall.testaop.controller.HelloController.helloAop()

返回值可以使用通配符*,表示任意返回值

* com.aismall.testaop.controller.HelloController.helloAop()

包名可以使用通配符,表示任意包,但是有几级包,就需要写几个*.

* *.*.*.*.HelloController.helloAop()

包名可以使用…表示当前包及其子包

* *...HelloController.helloAop()

类名和方法名都可以使用*来实现通配

* *..*.*()

参数列表:

1、可以直接写数据类型:

基本类型直接写名称 :例如,int

引用类型写包名.类名的方式 :例如,java.lang.String

可以使用通配符*表示任意类型,但是必须有参数

可以使用…表示有无参数均可,有参数可以是任意类型

2、全通配写法:* .*(…)

2、@annotation,带有相应注解的方法,比如对标有@Transactional注解的方法进行增强

@annotation(org.springframework.transaction.annotation.Transactional)

五、代码实战 —— execution(表达式)

使用aop来完成全局请求日志处理

在这里插入图片描述
1、创建个controller

@RestController
public class HelloController {
    @RequestMapping("/helloAop")
    public Object hello(){
        return "hello aop";
    }
    @RequestMapping("/helloError")
    public Object helloError(){
        return 1/0;
    }
}

2、创建一个aspect切面类

@Aspect
@Component
public class MyAop {
    //切入点:待增强的方法
    @Pointcut("execution(public * com.aismall.testaop.controller.*.*(..))")
    //切入点签名
    public void log(){
        System.out.println("pointCut签名。。。");
    }
    //前置通知
    @Before("log()")
    public void deBefore(JoinPoint jp) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
        System.out.println("HTTP_METHOD : " + request.getMethod());
        System.out.println("CLASS_METHOD : " + jp);
        System.out.println("ARGS : " + Arrays.toString(jp.getArgs()));

    }
    //返回通知
    @AfterReturning(returning = "ret", pointcut = "log()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        System.out.println("返回通知:方法的返回值 : " + ret);
    }

    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "log()")
    public void throwss(JoinPoint jp,Exception ex){
        System.out.println("异常通知:方法异常时执行.....");
        System.out.println("产生异常的方法:"+jp);
        System.out.println("异常种类:"+ex);
    }

    //后置通知
    @After("log()")
    public void after(JoinPoint jp){
        System.out.println("后置通知:最后且一定执行.....");
    }
}

3、启动项目

请求链接:http://localhost:8080/helloAop

控制台返回:

URL : http://localhost:8080/helloAop
HTTP_METHOD : GET
CLASS_METHOD : execution(Object com.aismall.testaop.controller.HelloController.hello())
ARGS : []
返回通知:方法的返回值 : hello aop
后置通知:最后且一定执行.....

分析:返回通知和异常通知只会执行一个,后置通知一定会执行。

六、代码实战二 —— @annotation方式

在这里插入图片描述
1、编写一个自定义注解

//表示次注解可以标注在类和方法上
@Target({ElementType.METHOD, ElementType.TYPE})
//运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAnnotation {
    //定义一个变量,可以接受参数
    String desc() default " ";
}

2、在HelloController类中添加一个方法

@RequestMapping("helloAnnotation")
//标有这个注解的方法会被增强
@MyLogAnnotation(desc = "@Annotation")
public Object helloAnnotation() {
    return "hello annotation";
}

3、切面类

@Aspect
@Component
public class MyAopAnnotation {
    //切入点:增强标有MyLogAnnotation注解的方法
    @Pointcut(value="@annotation(com.aismall.testaop.MyAnnotation.MyLogAnnotation)")
    //切入点签名
    public void logAnnotation(){
        System.out.println("pointCut签名。。。");
    }
    //前置通知
    @Before("logAnnotation()")
    public void deBefore(JoinPoint jp) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
    }
    //返回通知
    @AfterReturning(returning = "ret", pointcut = "logAnnotation()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        System.out.println("返回通知:方法的返回值 : " + ret);
    }

    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "logAnnotation()")
    public void throwss(JoinPoint jp,Exception ex){
        System.out.println("异常通知:方法异常时执行.....");
        System.out.println("产生异常的方法:"+jp);
        System.out.println("异常种类:"+ex);
    }

    //后置通知
    @After("logAnnotation()")
    public void after(JoinPoint jp){
        System.out.println("后置通知:最后且一定执行.....");
    }
}

4、启动项目

请求链接:http://localhost:8080/helloAnnotation

控制台显示:

URL : http://localhost:8080/helloAnnotation
返回通知:方法的返回值 : hello annotation
后置通知:最后且一定执行.....

七、环绕通知

环绕通知可以把前面的四种通知都表示出来,而且环绕通知一般单独使用

环绕通知的使用:

Spring框架为我们提供了一个接口:ProceedingJoinPoint,该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。

该接口作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。

增强代码写在调用proceed()方法之前为前置通知,之后为返回通知,写在catch中为异常通知,写在finally中为后置通知。

在这里插入图片描述

第一步:在HelloController类中添加一个方法

@RequestMapping("/helloAround")
public Object helloAround(){
    System.out.println("helloAround执行了。。。");
    return "hello around";
}

第二步:切面类

Aspect
@Component
public class MyAroundAop {
    //切入点:待增强的方法
    @Pointcut("execution(public * com.aismall.testaop.controller.*.*(..))")
    //切入点签名
    public void logAround() {
        System.out.println("pointCut签名。。。");
    }

    //环绕通知,环绕增强,相当于MethodInterceptor
    @Around("logAround()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) {
        Object rtValue = null;
        try {
            Object[] args = pjp.getArgs();//得到方法执行所需的参数

            System.out.println("通知类中的aroundAdvice方法执行了。。前置");

            rtValue = pjp.proceed(args);//明确调用切入点方法(切入点方法)

            System.out.println("通知类中的aroundAdvice方法执行了。。返回");
            System.out.println("返回通知:"+rtValue);

            return rtValue;
        } catch (Throwable e) {
            System.out.println("通知类中的aroundAdvice方法执行了。。异常");
            throw new RuntimeException(e);
        } finally {
            System.out.println("通知类中的aroundAdvice方法执行了。。后置");
        }
    }
}

第三步:启动项目

请求链接:http://localhost:8080/helloAround

控制台返回的结果:

通知类中的aroundAdvice方法执行了。。前置
helloAround执行了。。。
通知类中的aroundAdvice方法执行了。。返回
返回通知:hello around
通知类中的aroundAdvice方法执行了。。后置
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解 Springboot 中使用 Aop 的相关文章

随机推荐

  • Markdown / KaTex数学公式汇总

    目录 LaTex和KaTex 软件推荐 Mathpix 一 如何插入公式 二 上下标 三 常用运算符 四 高级运算符 五 常用数学符号 六 特殊符号 6 1 箭头 6 2 公式序号 七 括号使用 八 矩阵 九 集合运算 十 希腊字母 十一
  • 使用反射实现动态修改@Excel的注解属性

    业务场景 我们使用poi实现数据导出时 通常是根据 Excel name xxx 来确定列名 通常情况下这个是不会发生变动的 但这里就说少数情况 在我们需要这里根据某些情况来进行改变的时候 我们就需要用到反射 AirQualityRanki
  • Java反射(自己的理解)

    动态语言 运行是代码可以根据某些条件改变自身结构 像js和php python等 但是我们不像c 是一门静态语言 可以准确的说我们是一门准动态语言 因为反射让我们具有动态性 我来直接用我所理解的反射给大家先讲一下大概 这绝对让你的耳目一新
  • 五、单向散列函数

    单向散列函数 获取消息的指纹 当需要比较两条消息是否一致时 我们不必直接对比消息本身的内容 只要对比它们的 指纹 就可以了 单向散列函数 one wayftnction 有一个输人和一个输出 其中输人称为消息 message 输出称为散列值
  • 全国大学生数字建模竞赛、中国研究生数学建模竞赛(数学建模与计算实验)前言

    1 什么是数学建模 2 所需要学的知识 知识算法分类表格汇总 3 所需要的软件工具 4 论文模板 查找文献 查找数据 一 什么是数学建模 全国大学生数字建模竞赛 National College Student Mathematical M
  • HashMap源码初探

    Hash table based implementation of the Map interface This implementation provides all of the optional map operations and
  • Qt动态库加载之 QLibrary

    目录 一 使用Qt编译C动态库 二 使用QLibrary调用共享库 一 使用Qt编译C动态库 使用Qt新建一个C项目 cbb frame 在项目中我们声明和定义两个函数 并导出函数 在cbb mylog中我们使用了函数指针 这里为啥这样干
  • python人脸识别考勤系统 dlib+OpenCV和Pyqt5、数据库sqlite 人脸识别系统 计算机 毕业设计 源码

    一 项目介绍 Python语言 dlib OpenCV Pyqt5界面设计 sqlite3数据库 本系统使用dlib作为人脸识别工具 dlib提供一个方法可将人脸图片数据映射到128维度的空间向量 如果两张图片来源于同一个人 那么两个图片所
  • hrformer

    High Resolution Transformer Copyright c 2021 Microsoft Licensed under The MIT License see LICENSE for details Written by
  • keepalived 实现双机热备

    文章目录 一 说明 二 概念解释 三 环境准备 四 操作过程 五 验证 一 说明 我们经常听说 nginx keepalived 双机热备 其实在这里 双机热备有两种思路 一是只利用 keepalived 实现两个节点的故障切换 当主节点挂
  • 章节二:Vue.js的安装和配置

    2 1 下载和安装Vue js 要下载和安装Vue js 你有几个选项可供选择 通过CDN 在HTML文件中引入Vue js的CDN链接 然后直接使用Vue全局变量 使用包管理器 使用npm或yarn等包管理器 在项目中安装Vue js 下
  • 一文搞懂IP基础以及子网划分!!!!!

    1 什么是IP地址 IP地址 Internet Protocol Address 互联网国际地址 是一种在Internet上的给主机编址的方式 它主要是为互联网上的每一个网络和每一台主机分配一个逻辑地址 以此来屏蔽物理地址的差异 IP地址就
  • Reactjs鼠标滚轮监听

    1 添加相应的react所需的包及插件 npm install react s npm install react dom s 2 鼠标滚轮事件及引用子组件的滚轮处理事件 handleWheel function event 判断鼠标滚轮的
  • JavaBean配置

    在JSP内嵌入大量的Java代码可能会造成维护不方便 为此最好的方就是把JSP代码和Java代码分开 将JSP中的Java代码移植到Java类中 这些可能用到的类就是JavaBean JavaBean实现步骤如下 1 在src中新建一个be
  • 微型计算机上的南桥芯片功能,微型计算机主板上安装的主要部件

    如下 1 芯片组 芯片组是构成主板电路的核心 决定了主板的级别和档次 北桥芯片是主板上最重要的芯片 主要负责与CPU 内存 显卡进行通讯 南桥芯片负责连接硬盘 USB 接口 PCI 接口等其他接口 南桥芯片和北桥芯片之间也有联系 2 存储控
  • 洋桃电子STM32物联网入门30步笔记三、CubeMX图形化编程、设置开发板上的IO口

    此文档作为对杨桃电子视频的整理 B站链接 第四集 一 开启RCC的外部时钟 包括外部高速时钟HSE和外部低速时钟LSE 时钟配置三个选项的含义 选择禁用的话就只能使用内部时钟 旁路时钟源一般是有源晶振 晶体与陶瓷振荡器一般是无源晶振 二 开
  • 利用JS获取IE客户端IP及MAC的实现

    在做B S结构的系统时 我们常常需要获取客户端的一些信息 如IP和MAC 以结合身份验证 在ASP NET中 要获取服务器端的MAC很容易 但是要获取客户端的MAC的地址确要花费一翻心思 通常的做法是调用Win32API或直接调用nbtst
  • MySQL技术内幕InnoDB存储引擎 学习笔记 第六章 锁

    锁是数据库系统区别于文件系统的一个关键特性 锁机制用于管理对共享资源的并发访问 InnoDB引擎会对表数据上锁以提供数据的完整性和一致性 除此之外 还会对数据库内部其他多个地方使用锁 从而保证对多种不同资源提供并发访问 如增删改LRU列表中
  • 基于Centos7+pycharm搭建python获取爬虫小项目

    一 安装python环境 网上教程查阅 安装成功后运行 python 查看版本 python V 二 安装pycharm 应在步骤一完成后进行 到pycharm官网下载最新版本 下载链接 https www jetbrains com py
  • 详解 Springboot 中使用 Aop

    一 什么是 Aop AOP Aspect Oriented Programming 意为面向切面编程 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术 AOP的编程思想是把对类对象的横切问题点 从