Spring AOP 简介

一、Spring AOP

AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现。

1、什么是 AOP?

AOP(Aspect Oriented Programming):是一种编程思想,表示面向切面编程。指的是对某一类事情的集中处理

举一个常见的例子,当我们实现用户登录校验的时候,如果有多个网页都有同样的需求,那么我们传统的写法是在每个页面都写一个校验逻辑,这就会导致代码的可维护性降低。而如果我们使用
AOP 的思想,就可以对这种功能一致,且多次使用的功能进行统一的处理。

通过上面的例子,我们可以归纳出 AOP 的应用场景:

  • 统一的用户登录判断
  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等

对于 AOP 来说,它可以扩充多个对象的某个能力,因此通常认为 AOP 是 OOP(Object Oriented Programming,面向对象编程)的补充和完善。

2、AOP 的组成

切面(Aspect):定义的是事件,描述了当前 AOP 的作用。是包含了 切点和通知 的类。例如定义当前AOP是进行统一用户登录判断的。

连接点(Join Point):连接点是在应用程序执行过程中可以插入切面的点,切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。典型的连接点包括方法调用、方法执行、异常抛出等。

切点(Pointcut):定义匹配 Join Point 的规则,给满足规则的 Join Point 添加 Advice。例如定义哪些接口判断用户登录权限,哪些不判断。

通知(Advice):AOP 执行方法的具体实现 。例如通过获取用户的 session 信息,判断用户登录状态。

在Spring AOP 中提供了以下五种类型的通知:

  1. 前置通知(@Before):通知方法会在目标方法调用之前执行。
  2. 后置通知(@After):通知方法会在目标方法返回或者抛出异常后调用。
  3. 返回通知(@AfterReturning):通知方法会在目标方法返回后调用。
  4. 异常通知(@AfterThrowing):通知方法会在目标方法抛出异常后调用。
  5. 环绕通知(@Around):通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

二、Spring AOP 实现

下面我们使用 Spring AOP 来完成拦截所有 UserController 里的方法,每次调用 UserController 中任意一个方法时,都执行相应的通知事件。

1、添加 AOP 框架支持

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、定义切面类

定义切面使用的是 @Aspect

@Aspect
@Component
public class UserAspect {}

3、定义切点

定义切点使用 @Pointcut 注解,可在参数中定义匹配 Joint Point 的规则(这里使用的是 AspectJ 语法)

@Aspect
@Component
public class UserAspect {// 定义切点,使用 AspectJ 语法// 该切点规则将匹配 com.example.demo.controller.UserController 类// 中的所有方法,无论方法的返回类型和参数列表如何@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointCut(){}
}

4、实现通知

对于 前置通知、后置通知、返回通知、异常通知 的实现都如出一辙,并且非常简单,只需要添加给通知方法添加响应通知注解即可:

@Aspect
@Component
public class UserAspect {// 定义切点,使用 AspectJ 语法@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointCut(){}// 前置通知@Before("pointCut()")public void doBefore(){System.out.println("执行doBefore()前置通知!");}// 后置通知@After("pointCut()")public void doAfter(){System.out.println("执行doAfter()后置通知!");}// 返回通知@AfterReturning("pointCut()")public void doAfterReturn(){System.out.println("执行doAfterReturn()了返回通知");}// 异常通知@AfterThrowing("pointCut()")public void doAfterThrowing(){System.out.println("执行了doAfterThrowing()异常通知");}}

比较复杂的是环回通知的实现,环回通知有它固定的格式:

@Aspect
@Component
public class UserAspect {// 定义切点,使用 AspectJ 语法@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointCut() {}// 环绕通知@Around("pointCut()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around ⽅法开始执⾏");// 执行目标方法Object obj = joinPoint.proceed();System.out.println("Around ⽅法结束执⾏");return obj;}
}

其中 ProceedingJoinPoint 在环绕通知中可以控制目标方法的执行。通过调用 joinPoint.proceed() 可以触发目标方法的执行。如果目标方法有返回值,当目标方法执行完毕后,它会被保存在 obj 变量中,作为整个环绕通知方法的返回值返回给调用方。

调用 UserController 中的方法,得到测试结果:

三、Spring AOP 实现原理

Spring AOP 是构建在动态代理基础上的。Spring 的切面是由包裹了目标对象的代理实现的,代理类处理方法的调用,执行额外的切面逻辑,并调用目标方法。

Spring AOP 支持 JDK Proxy 动态代理和 CGLIB 动态代理技术,它们主要有以下区别:

  1. JDK Proxy 来自于 Java 本身,CGLIB 来自于第三方。
  2. JDK Proxy 动态代理是基于接口的,要求代理类必须实现接口才能实现代理;CGLIB 动态代理是基于类的,通过继承被代理类完成动态代理,因此要求被代理类不能是 final 修饰的类。
  3. 在 JDK 8 以上的版本中,JDK Proxy 动态代理做了专门的优化,所以性能比 CGLIB 高。

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

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

相关文章

小程序video标签在底部出现1px无法去除的黑色线

问题描述 参见社区问题详情 此问题只会在ios手机真机中出现&#xff0c;视频底部出现1px无法去除的黑色线 解决方法 1.尝试过video各种配置&#xff0c;以为是设置参数导致 2.尝试过父元素设置height&#xff1a;200px&#xff1b;overflow&#xff1a;hidden&#xff1b;vi…

python栈_简单算术表达式_加减乘除

# 从左到右遍历中缀表达式中的每个数字和符号&#xff0c;若是数字就输出&#xff0c;即成为后缀表达式的一部分&#xff1b;若是符号则要分为两种情况&#xff1a; # (1)是括号时&#xff0c;如果是左括号&#xff0c;直接将左括号入栈&#xff0c;如果是右括号则栈顶元素依次…

插件_日期_lunar-calendar公历农历转换

现在存在某需求&#xff0c;需要将公历、农历日期进行相互转换&#xff0c;在此借助lunar-calendar插件完成。 下载 [1] 通过npm安装 npm install lunar-calendar[2]通过文件方式引入 <script type"text/javascript" src"lib/LunarCalendar.min.js">…

2.3 矩阵消元

一、消元矩阵 消元矩阵执行消元步骤用到的矩阵。从第 i i i 个方程减去 l i j l_{ij} lij​ 乘第 j j j 个方程&#xff08;将 x j x_j xj​ 从第 i i i 行中消去&#xff09;。我们需要很多个简单的矩阵 E i j E_{ij} Eij​&#xff0c;每一个对应一个主对角线下方要消…

React 项目结构小结

React 项目结构小结 简单的记录一下目前 React 项目用的依赖和实现 摸索了大半年了大概构建一套用起来还算轻松的体系……&#xff1f;基本上应该是说可以应对大部分的项目了 使用的依赖 目前项目还在 refactoring 的阶段&#xff0c;所以乱得很&#xff0c;这里是新建一个…

有什么好用的CRM客户管理系统?推荐这5大高口碑的CRM系统!

有什么好用的CRM客户管理系统&#xff1f;推荐这5大高口碑的CRM系统&#xff01; 好用的CRM客户管理系统&#xff1a; ①需要进行精细化管理 ②需要专业的管理工具 ③最好能够做到和erp系统和oa系统的集成 授人以鱼不如授人以渔&#xff0c;在给题主推荐crm系统之前&#…

MySQL 是否大小写敏感

本文未做特别说明的&#xff0c;指同时适用于 MySQL 5.7 和 MySQL 8.x。 先说结论&#xff1a; 数据库、表名&#xff08;包括别名&#xff09;、触发器名是否大小写敏感与操作系统以及 MySQL 配置有关。列名&#xff08;包括别名&#xff09;、索引、存储过程和事件名称大小写…

高数笔记06:无穷级数

图源&#xff1a;文心一言 时间比较紧张&#xff0c;仅导图~~&#x1f95d;&#x1f95d; 第1版&#xff1a;查资料、画导图~&#x1f9e9;&#x1f9e9; 参考资料&#xff1a;《高等数学 基础篇》武忠祥 &#x1f433;目录 &#x1f433;常数项级数 &#x1f40b;概要 &…

C++基础——对于C语言缺点的补充(2)

上篇文章中说到&#xff0c;为了解决C语言会出现人为定义的函数和库函数出现重定义的错误&#xff0c;C引入了一个新的概念&#xff0c;即命名空间&#xff0c;通过认为定义命名空间&#xff0c;来解决上述问题。 在本篇文章中&#xff0c;将继续介绍C相对于C语言不足来进行的补…

Node.js、Chrome V8 引擎、非阻塞式I/O介绍

目录 Node.js介绍Chrome V8 引擎介绍非阻塞式I/O介绍 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你的青睐是我努力的方向&#xff01; ✏️ 评论&#xff0c;你的意见是我进步的财富&#xff01; Node.js介绍 Node.js 是一个…

Harbor企业级Registry基础镜像仓库的详细安装使用教程(保姆级)

Harbor Docker 官方提供的私有仓库 registry&#xff0c;用起来虽然简单 &#xff0c;但在管理的功能上存在不足。 Harbor是vmware一个用于存储和分发Docker镜像的企业级Registry服务器&#xff0c;harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。 ha…

数据结构之堆的实现(图解➕源代码)

一、堆的定义 首先明确堆是一种特殊的完全二叉树&#xff0c;分为大根堆和小根堆&#xff0c;接下来我们就分别介绍一下这两种不同的堆。 1.1 大根堆&#xff08;简称&#xff1a;大堆&#xff09; 在大堆里面&#xff1a;父节点的值 ≥ 孩子节点的值 我们的兄弟节点没有限制&…

pandas 笔记:get_dummies分类变量one-hot化

1 函数介绍 pandas.get_dummies 是 pandas 库中的一个函数&#xff0c;它用于将分类变量转换为哑变量/指示变量。所谓的哑变量&#xff0c;就是将分类变量的每一个不同的值转换为一个新的0/1变量。在输出的DataFrame中&#xff0c;每一列都以该值的名称命名 pandas.get_dummi…

java使用bouncycastle加解密

jdk默认带了一些常见的加解密方式&#xff0c;当我们常见的加解密不能满足时&#xff0c;就需要用到一些第三方的库了&#xff0c;bouncycastle就是其中一种。 但是bouncycastle文档比较少。简单介绍一下写法 1.导入依赖 <dependency><groupId>org.bouncycastle&…

5 ip的分配

如上一节所述&#xff0c;需要和其他设备通信&#xff0c;那么需要先配置ip. 1、如何配置ip 1.可以使用 ifconfig&#xff0c;也可以使用 ip addr 2.设置好了以后&#xff0c;用这两个命令&#xff0c;将网卡 up 一下&#xff0c;就可以了 //---------------------------- 使…

AI大模型时代网络安全攻防对抗升级,瑞数信息变革“下一代应用与数据安全”

AI与大模型技术加速普及&#xff0c;安全领域也在以创新视角聚焦下一代应用安全WAAP变革&#xff0c;拓展新一代数据安全领域。近日瑞数信息重磅发布了瑞数全新API扫描器、API安全审计、数据安全检测与应急响应系统及分布式数据库备份系统四大新品。此次发布在延续瑞数信息Bot自…

用java代码实现QQ第三方登录

QQ第三方登录需要使用到QQ互联开放平台提供的API&#xff0c;在Java中可以使用OAuth2.0协议来实现第三方登录。 具体实现步骤如下&#xff1a; 注册QQ互联开放平台账号&#xff0c;并创建应用&#xff0c;获取到App ID和App Secret。 在Java项目中导入QQ互联开放平台提供的Ja…

当zmq 和 docker 都要绑定一个端口时,怎么不修改端口号就能解决冲突?

问题描述 docker容器中的程序需要和外部进行通讯&#xff0c;但是当作为请求方向 响应方发送数据时&#xff0c;外部的进程因为需要绑定的端口被docker占用而绑定失败。 解决方式 方式一&#xff1a;使用请求响应方式&#xff0c;但是将响应端放置到容器内部。 方拾二&#…

freertos简单串口

先来完善一下FreeRTOSConfig.h这个配置文件 /*FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.All rights reservedVISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.This file is part of the FreeRTOS distribution.FreeRTOS is …

vue3+ts+vite搭建项目

检查node版本 > node -v检查vue版本 > vue -V1、全局安装Vue CLI 3.X版本 > npm install -g vue/cli2、创建vue 项目 > vue create [project-name]3、安装vite > npm install vite4、使用vite Vite 需要 Node.js 版本 > 12.0.0。 > npm init vitela…