当前位置: 首页 > news >正文

【Spring】什么是 AOP(面向切面编程) ? 为什么要有 AOP ? 如何实现 Spring AOP ?

文章目录

  • 前言
  • 一、什么是 AOP ?
  • 二、为什么要使用 AOP ?
  • 三、 AOP 的组成
  • 四、Spring AOP 的实现
    • 1, 添加依赖
    • 2, 定义切面
    • 3, 定义切点
    • 4, 定义通知
    • 5, 创建连接点
  • 总结


前言

各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你:
📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
📗 Java数据结构: 顺序表, 链表, 堆, 二叉树, 二叉搜索树, 哈希表等
📘 JavaEE初阶: 多线程, 网络编程, TCP/IP协议, HTTP协议, Tomcat, Servlet, Linux, JVM等(正在持续更新)

在这里插入图片描述


提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!


一、什么是 AOP ?

AOP(Aspect Oriented Programming)面向切面编程, 这是一种思想, 是对某一类事情的集中处理, 其核心思想是将那些与业务逻辑无关, 但是被多处业务逻辑模块共享的代码(比如判断用户登录, 日志管理, 权限检查, 事务管理等)抽取出来集中处理, 这样, 开发者可以将更多的精力放在处理核心业务逻辑上

Spring AOP 是一个框架, 对 AOP 思想的一种实现


二、为什么要使用 AOP ?

基本上每一个 Web 项目(会故意一下你使用过的网站或 APP ), 都有用户登录功能, 对于一个网站来说, 除了登录页和注册页, 基本上每个页面都有用户登录之后才能进行的操作, 那么这些页面都要在 controller 层进行校验用户登录之后才能编写业务代码

然而当你的功能越来越多, 那么你要写的登录验证也越来越多, 但这些方法又是相同的,这么多的方法就会代码修改和维护的成本, 对于这种功能统一的需求, 更简单方便的方式就是 AOP

AOP 可以扩充多个对象的某个能力, 所以 AOP 可以说是 OOP(Object Oriented
Programming, 面向对象编程)的补充和完善


三、 AOP 的组成

  • 切面(通常是一个类)
    指的是某一类事情的具体内容, 比如用户登录校验就是一个切面, 日志统一记录也是一个切面, 通常切面是一个类

切面是包含了:通知切点切面的类, 相当于 AOP 实现的某个功能的集合
可以把切面看作是一个模块, 它的目标是完成一些特定的工作, 这些工作通过通知实现, 而切点则确定了这些工作应当在何处执行。

  • 切点 (通常是一个方法)
    切点用来定义 AOP 拦截的规则的(使用AspectJ pointcut expression language 来描述), 通常是类中的一个方法, 该方法不需要实现, 只是一个标识, 后面用代码展示

所谓的拦截规则其实就是你的 通知 应该在何处执行
你可以将切点视为一个包含了多个连接点的集合, 这个集合中的每个元素(即每个连接点)都将应用通知(执行通知中的方法)

  • 连接点(通常也是方法)
    所有可能触发切点的点就称之为连接点

连接点是程序执行的某个特定位置, 如类的某个方法调用前、调用后、方法捕获到异常后等, 在Spring AOP中, 一个连接点总是代表一个方法的执行

  • 通知 (方法具体实现代码)
    切面也是有目标的 ——它要必须完成什么工作? 在 AOP 术语中, 切面的工作被称之为通知

Spring 切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用

  1. 前置通知 @Before:这个注解标注的方法会在目标方法(实际要执行的方法)被调用前执行
  2. 后置通知 @After:这个注解标注的方法会在目标方法完成后执行, 无论目标方法是否成功完成
  3. 环绕通知 @Around:这个注解标注的方法会在目标方法调用前后都执行, 可以自行决定何时执行目标方法
  4. 异常通知 @AfterThrowing:这个注解标注的方法会在目标方法抛出异常后执行
  5. 方法返回通知 @AfterReturning:这个注解标注的方法会在目标方法成功返回后执行

四、Spring AOP 的实现

我们用 Spring AOP 来实现⼀下 AOP 的功能, 完成的目标是拦截所有 UserController 里的方法, 每次调用 UserController 中任意方法时(拦截到), 都执行相应的通知事件


1, 添加依赖

把下面这段代码拷贝到 pom.xml

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

2, 定义切面

@Aspect // 定义该类为切面
@Component // 随框架加载而加载
public class UserAspect {}

3, 定义切点

@Aspect // 定义该类为切面
@Component // 随框架加载而加载
public class UserAspect {// 切点(下面这段字符串就是用来定义拦截规则的)@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointCut(){}
}

pointcut() 为空方法, 它不需要有方法体, 此方法名就是起到⼀个 “标识/关联” 的作用, 标识 通知方法 具体指的是哪个切点(因为切点可能有很多个)

Aspect 语法中的通配符

  • * : 表示匹配任意的内容, 用在返回值, 包名, 类名, 方法都可以使用
  • ..: 匹配任意字符,可以使用在方法参数上, 如果用在类上需要配合 * 一起使用
  • + : 表示匹配指定类及其它底下的所有子类, 比如 com.UserController+ 表示匹配 com.UserController 及其所有子类

AspectJ 语法(Spring AOP 切点的匹配方法)

切点表达式由切点函数组成, 其中 execution() 是最常用的切点函数, 用来匹配方法, 语法为: execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>)

  • 修饰符(一般省略):public(公共方法), *(任意)
  • 返回类型(不能省略):void, String, int, *(任意)
  • 包:com.demo(固定包), com.*( com 包下所有), com.demo..( com.demo 包下所有子包含自己)
  • 类:Test (固定类),Test* (以 Test 开头),*Test(以 Test 结尾),*(任意)
  • 方法名(不能省略):addUser(固定方法), add*(以 add 开头), *add(以 add 结尾), *(任意)
  • 参数:(), (int), (int,String), (…)任意参数
  • 异常(可省略, 一般不写)

4, 定义通知

注意看, 在下面各种通知方法的注解中, 参数为 “pointCut()” , 这就和上面写的切点方法关联上了

配合 System.currentTimeMillis() 观察这些通知方法具体的执行时机

@Aspect // 定义该类为切面
@Component // 随框架加载而加载
public class UserAspect {// 切点@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointCut(){}// 前置通知@Before("pointCut()")public void doBefore(){System.out.println("执行前置通知 " + System.currentTimeMillis());}// 后置通知@After("pointCut()")public void doAfter(){System.out.println("执行 后置通知 " + System.currentTimeMillis());}// return 之前通知@AfterReturning("pointCut()")public void doAfterReturning(){System.out.println("执⾏ 返回后通知 " + System.currentTimeMillis());}// 抛出异常之前通知@AfterThrowing("pointCut()")public void doAfterThrowing() {System.out.println("执⾏ 异常后通知 " + System.currentTimeMillis());}// 环绕通知@Around("pointCut()") // 参数是拿到目标方法的执行对象public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("环绕通知 执行开始 " + System.currentTimeMillis());Object object = null;object = joinPoint.proceed();// 执行目标方法System.out.println("环绕通知 执行结束 " + System.currentTimeMillis());return object;}
}

环绕通知带有参数, 参数 joinPoint 的意义就是拿到目标方法(要执行的方法就是目标方法, 比如下面的 sayHi() )的执行对象, 也就是 UserController 中的所有方法的执行对象. 用这个对象调用 proceed() 就是执行 UserController 中的所有方法. 环绕通知的返回值和目标方法的方法类型无关, 它只决定框架能否继续执行后续流程

5, 创建连接点

在 Controller 类下面定义

@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/sayhi")public String sayHi(){System.out.println("hi~ " + System.currentTimeMillis());return "hi~" + System.currentTimeMillis();}
}

运行项目, 访问 http://127.0.0.1:8080/user/sayhi

在这里插入图片描述

在这里插入图片描述

环绕通知的前置方法在最前面执行, 环绕通知的后置方法在最后执行
因为切点方法中使用了 AspectJ 语法规定了拦截路径, 所以 Controller 类下面的这个 sayHi() 才会被拦截, 执行这些通知方法


总结

以上就是本篇的所有内容了, 如果本篇对你有帮助,请点赞收藏支持一下,小手一抖就是对作者莫大的鼓励啦😋😋😋~


上山总比下山辛苦
下篇文章见

在这里插入图片描述

相关文章:

【Spring】什么是 AOP(面向切面编程) ? 为什么要有 AOP ? 如何实现 Spring AOP ?

文章目录 前言一、什么是 AOP ?二、为什么要使用 AOP ?三、 AOP 的组成四、Spring AOP 的实现1, 添加依赖2, 定义切面3, 定义切点4, 定义通知5, 创建连接点 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法…...

11.并发:自旋锁

原子操作和自旋锁的区别 相同点都是保护共享资源。 不同点在于&#xff1a; 原子操作简单易用&#xff0c;但只能做计数操作&#xff0c;保护的东西太少。 自旋锁主要用于多核处理器。短时期的轻量级加锁&#xff0c;加锁失败时原地打转、忙等待。避免了上下文调度和系统开销较…...

使用EF Core更新与修改生产数据库

使用EF Core的Code First&#xff0c;在设计阶段&#xff0c;直接使用Database.EnsureCreated()和EnsureDeleted()可以快速删除、更新最新的数据结构。由于没有什么数据&#xff0c;删除的风险非常低。但是对于已经投入生产的数据库&#xff0c;这个方法就绝对不可行了。 考虑…...

法律小程序开发:让法律咨询更便捷

在现代社会&#xff0c;法律咨询服务越来越受到人们的重视和需求。为了方便用户预约法律咨询&#xff0c;很多律所都开始使用小程序来提供在线预约服务。那么&#xff0c;如何制作一款律所预约小程序呢&#xff1f; 首先&#xff0c;我们可以选择乔拓云网作为制作小程序的平台。…...

【C++多线程】C++11互斥锁和条件变量实现生产者消费者模型

先看几个问题&#xff0c;第三个问题可以先看代码然后再理解 Q1&#xff1a;临界区在哪 A1: 队列中元素在「生产者生产&#xff08;push&#xff09;」和「消费者消费&#xff08;pop&#xff09;」时就是临界区 Q2&#xff1a;同步操作在哪 A2: 很显然&#xff0c;队列只有…...

Webpack迁移Vite采坑指南

前言 本文不介绍什么是webpack、什么是vite&#xff0c;也不分析为什么要迁移。如果你想从webpack迁移到vite&#xff0c;你可能会遇到一些坑&#xff0c;这里我会尽量详细地介绍每一种可能遇到的坑以及解决办法。 老规矩&#xff0c;先说AI的评价&#xff1a;这篇从webpack迁…...

设计模式-职责链模式

文章目录 职责链模式模式概述主要角色适用场景实现步骤优点注意事项 定义职责链结构示例总结 职责链模式 职责链模式是一种行为设计模式&#xff0c;它可以将请求的发送者和请求的处理者解耦&#xff0c;并按照预定义的顺序处理请求。职责链模式常用于需要逐级审批或转交处理的…...

CMake学习笔记-VSCode使用Cmake编译C++工程

环境 Win MinGW CMake Git 单文件工程 # 1 指定最小版本号 cmake_minimum_required(VERSION 3.10) # 2 指定工程名 project(Tutorial) # 3 设置编译器路径 set(CMAKE_C_COMPILER "D:/ProgramPackage/mingw64/mingw64/bin/gcc.exe") set(CMAKE_CXX_COMPILER &q…...

redis相关

如果redis没有设置expire&#xff0c;他是否默认永不过期&#xff1f; 清理线上Redis没有设置过期时间的key_青苔小榭的博客-CSDN博客 如何给Redis中未设置过期时间key添加过期时间&#xff1f; - 知乎 Redis中的几种更新策略_如何实现redis数据的局部更新_LG_985938339的博客…...

【VRTK4.0运动专题】轴移动AxisMove(真实身体的移动)

文章目录 1、概览2、释义3、属性设置 1、概览 2、释义 “竖直轴”控制的行为“水平轴”控制的行为1Vertical-Slide 滑动Horizontal-Slide 滑动2Vertical-Slide 滑动Horizontal-SmoothRotate 转动3Vertical-Slide 滑动Horizontal-SnapRotate 转动&#xff08;不连续&#xff09…...

【vue2-helper插件】提供Mixins和组件库相关的类型提示、智能补全、跳转等功能~

Vue2-helper - 为你的 Vue2 开发增添智慧 ✨ &#x1f680; 辅助Vue2开发中的Mixins、组件库、Vue-router的智能补全、语义高亮、跳转支持、Hover 提示等&#xff0c;提升Vue2开发体验。 功能特色 ✨ ✅ 配置式缓存设计&#xff1a;秒级切换体验&#xff0c;让开发如丝般顺滑…...

论文解读 | ScanNet:室内场景的丰富注释3D重建

原创 | 文 BFT机器人 大型的、有标记的数据集的可用性是为了利用做有监督的深度学习方法的一个关键要求。但是在RGB-D场景理解的背景下&#xff0c;可用的数据非常少,通常是当前的数据集覆盖了一小范围的场景视图&#xff0c;并且具有有限的语义注释。 为了解决这个问题&#…...

手写数字识别之网络结构

目录 手写数字识别之网络结构 数据处理 经典的全连接神经网络 卷积神经网络 手写数字识别之网络结构 无论是牛顿第二定律任务&#xff0c;还是房价预测任务&#xff0c;输入特征和输出预测值之间的关系均可以使用“直线”刻画&#xff08;使用线性方程来表达&#xff09…...

《动手深度学习》 线性回归从零开始实现实例

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…...

Redis 命令

Redis 命令 Redis 命令用于在 redis 服务上执行操作。 要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。 语法 Redis 客户端的基本语法为&#xff1a; $ redis-cli实例 以下实例讲解了如何启动 redis 客户端&#xf…...

Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

文章目录&#xff1a; 一&#xff1a;线程池模块分析 threadpool.c 二&#xff1a;UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三&#xff1a;套接字 1.本地套接字 2.本地套 和 网络套对比 server.c client.c 一&#xff1a;线…...

nvm安装electron开发与编译环境

electron总是安装失败&#xff0c;下面说一下配置办法 下载软件 nvm npmmirror 镜像站 安装nvm 首先最好卸载node&#xff0c;不卸载的话&#xff0c;安装nvm会提示是否由其接管&#xff0c;保险起见还是卸载 下载win中的安装包 配置加速节点nvm node_mirror https://npmmi…...

玩转Mysql系列 - 第7篇:玩转select条件查询,避免采坑

这是Mysql系列第7篇。 环境&#xff1a;mysql5.7.25&#xff0c;cmd命令中进行演示。 电商中&#xff1a;我们想查看某个用户所有的订单&#xff0c;或者想查看某个用户在某个时间段内所有的订单&#xff0c;此时我们需要对订单表数据进行筛选&#xff0c;按照用户、时间进行…...

启动程序结束程序打开指定网页

import subprocess subprocess.Popen(r"C:\\Program Files\\5EClient\\5EClient.exe") # 打开指定程序 import os os.system(TASKKILL /F /IM notepad.exe) # 结束指定程序 import webbrowser webbrowser.open_new_tab(https://www.baidu.com) # 打开指定网页...

从零开始学习 Java:简单易懂的入门指南之包装类(十九)

包装类 包装类5.1 概述5.2 Integer类5.3 装箱与拆箱5.4 自动装箱与自动拆箱5.5 基本类型与字符串之间的转换基本类型转换为StringString转换成基本类型 5.6 底层原理 算法小题练习一&#xff1a;练习二&#xff1a;练习三&#xff1a;练习四&#xff1a;练习五&#xff1a; 包装…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...