Spring AOP(面向切面编程)的详细讲解

1.什么是 AOP?

AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的集中处理
AOP是一种思想,而Spring AOP是一个实现了AOP的思想框架,他们的关系和IOC与DI类似

2.为什要⽤ AOP?

想象⼀个场景,我们在做后台系统时,除了登录和注册等⼏个功能不需要做⽤户登录验证之外,其他⼏乎所有⻚⾯调⽤的前端控制器(Controller)都需要先验证⽤户登录的状态,那这个时候我们要怎么处理呢?

我们之前的处理⽅式是每个 Controller都要写⼀遍⽤户登录验证,然⽽当你的功能越来越多,那么你要写的登录验证也越来越多,⽽这些⽅法⼜是相同的,这么多的⽅法就会代码修改和维护的成本。那有没有简单的处理⽅案呢?

有人说可以抽取一个公共方法出来,每次需要验证的时候去调用这个方法就好了
这样做是可以的,但是还存在一个问题,如果登陆方法的参数发生改变,那么每个调用者都需要跟着修改,这样就会变得复杂,并且代码之间耦合严重,我们要尽量避免这种情况

开发的三个阶段:

  1. 初级阶段:每个方法都实现
  2. 中级阶段:抽取公共方法
  3. 高级阶段:采用AOP的方式

所以,对于这种功能统⼀,且使⽤的地⽅较多的功能,就可以考虑 AOP来统⼀处理了
除了统⼀的⽤户登录判断之外,AOP 还可以实现:

  • 统⼀⽇志记录
  • 统⼀⽅法执⾏时间统计(在性能优化阶段,监控流量,接口的响应时间等甚至每个方法的响应时间,为整个项目的性能进行优化)
  • 统⼀的返回格式设置 (对于接口的返回格式,基本上都是code,message,data)
  • 统⼀的异常处理
  • 事务的开启和提交等

也就是说使⽤AOP 可以扩充多个对象的某个能⼒,所以 AOP 可以说是 OOP(Object OrientedProgramming,⾯向对象编程)的补充和完善

3.Spring AOP 应该怎么学习呢?

Spring AOP 学习主要分为以下 3 个部分:

  1. 学习 AOP 是如何组成的?也就是学习 AOP 组成的相关概念。
  2. 学习 Spring AOP 使⽤。
  3. 学习 Spring AOP 实现原理。

3.1 AOP 组成

1 切⾯(Aspect)

切⾯(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。

切⾯是包含了:通知、切点和切⾯的类,相当于 AOP 实现的某个功能的集合

2 连接点(Join Point)

应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是⽅法调⽤时,抛出异常时,甚⾄修改字段时。切⾯代码可以利⽤这些点插⼊到应⽤的正常流程之中,并添加新的⾏为

连接点相当于需要被增强的某个 AOP 功能的所有⽅法

3 切点(Pointcut)

Pointcut 的作⽤就是提供⼀组规则(使⽤ AspectJ pointcut expression language 来描述)来匹配 Join Point,给满⾜规则的 Join Point 添加 Advice

切点相当于保存了众多连接点的⼀个集合(如果把切点看成⼀个表,⽽连接点就是表中⼀条⼀条 的数据)

4 通知(Advice)

通知:定义了切⾯是什么,何时使⽤,其描述了切⾯要完成的⼯作,还解决何时执⾏这个⼯作的问题

AOP是对于同一类事情(范围)集中处理(处理的内容是什么)
对于AOP而言,处理的内容就是通知,切⾯的⼯作被称之为通知

Spring 切⾯类中,可以在⽅法上使⽤以下注解,会设置⽅法为通知⽅法,在满⾜条件后会通知本⽅法进⾏调⽤:

  • 前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
  • 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤
  • 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
  • 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
  • 环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执 ⾏⾃定义的⾏为。
    在jointPoint.proceed()前后都可以通知
    注意:返回结果需要自己定义

4.我们就以用户登陆验证来举例:

1.首先我们需要创建一个springMVC的项目

参考博客:
spring项目的创建

2.在pop.xml中添加以下配置

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

3.创建一个UserController类,模拟用户需要执行的一些方法

/*** 用户需要调用的一些方法*/
@Slf4j // 用来打印日志的
@RestController
@RequestMapping("/user")
public class UserController {// 获取用户信息@RequestMapping("/get")public String getInfo() {return "获取信息";}// 注册@RequestMapping("/reg")public String reg() {return "注册";}// 登录@RequestMapping("/log")public String log() {return "登录";}}

4.定义切面和切点

切面就是具体要处理的某一类问题,(比如用户登录权限验证就是一个具体的问题)切点的作用就是制定一组规则,(比如在这里我们就要制定哪些方法可以走到切面的类里面来,就是拦截那些需要验证用户身份的操作)

@pointcut()注解内的切点表达式说明

1.AspectJ ⽀持三种通配符

在这里插入图片描述
切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为:
execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>)
在这里插入图片描述

2.表达式示例

在这里插入图片描述

@Slf4j // 用来打印日志的
@Component // 将此类交给spring容器来管理
@Aspect // 表示此类为一个切面
public class LoginAspect {// 定义一个切点@Pointcut("execution(* com.example.springaop.controller.UserController.* (..))")public void pointcut() {//其中 pointcut ⽅法为空⽅法,它不需要有⽅法体,此⽅法名就是起到⼀个“标识”的作⽤,标识下⾯的通知⽅法具体指的是哪个切点(因为切点可能有很多个)}
}

其中 pointcut ⽅法为空⽅法,它不需要有⽅法体,此⽅法名就是起到⼀个“标识”的作⽤,标识下⾯的通知⽅法具体指的是哪个切点(因为切点可能有很多个)

5.此时我们来测试一下通知方法注解

通知里就是要定义被切点拦截过来的方法具体要执行的业务,比如用户登陆的权限验证就是具体要执行的业务,在SpringAOP中,可以在方法上加以下注解,该方法就会变为通知方法,在满足条件后就会被调用

1.前置通知使⽤ @Before

通知方法在目标方法(就是连接点)执行之前调用

    @Before("pointcut()")public void doBefore() {log.info("doBefore...");}

此时我们在浏览器去搜索(假装登陆操作)
在这里插入图片描述
我们查看日志就可以发现在登陆操作之前,执行了Before注解的方法
在这里插入图片描述

2.后置通知使⽤ @After

该方法会在连接点(也就是目标方法)返回之后调用执行,或者抛出异常之后也会调用

    @After("pointcut()")public void doAfter() {log.info("doAfter...");}

此时去浏览器搜索之后发现在登陆操作之后,执行了@After注解的方法
在这里插入图片描述

3.返回之后通知使⽤ @AfterReturning

这个通知方法和@After都实在目标方法返回之后才调用,那么这两个的先后执行顺序是怎么样的呢?
我们来测试一下

    @AfterReturning("pointcut()")public void doAfterReturning() {log.info("doAfterReturning...");}

在浏览器操作后,查看日志发现@doAfterRuturning注解的方法比@After注解的方法先执行,但是@After还可以在抛出异常时调用,而且一般这两个不会同时使用
在这里插入图片描述

4.抛异常后通知使⽤ @AfterThrowing

该方法会在连接点抛出异常后调用
这个方法和@After注解,都拥有这个功能,那么这两个方法执行的先后顺序如何呢?
我们来测试一下

    @AfterThrowing("pointcut()")public void doAfterThrowing() {log.info("doAfterThrowing...");}

我们查看日志发现,@AfterThrowing同样是比@After注解的方法先执行
在这里插入图片描述

5.环绕通知使⽤ @Around(使用最多)

该方法包裹了连接点(也就是目标方法),在连接点通知之前和调用之后执行自定义的行为
注意:环绕通知的返回结果需要自己定义

    @Around("pointcut()")public Object doAround(ProceedingJoinPoint joinPoint) {// 传入当前的连接点// 定义返回结果Object oj = null;log.info("环绕通知执行之前...");try {// 调用目标方法oj = joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}log.info("环绕通知执行之后...");return oj;}

此时我们查看日志,可以看见在连接点通知之前和调用之后都执行了环绕通知自定义的行为
在这里插入图片描述

6.实际应用

这样我们就可以在使用切点制定一组规则,(设置连接点)拦截需要验证身份的方法,使得他们在执行前都调用一下身份验证,就像这样:

    @Around("pointcut()")public Object VerifyIdentity(ProceedingJoinPoint joinPoint) {Object oj = null;log.info("身份验证的方法");try {// 执行目标方法oj = joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}return oj;}

我们在浏览器分别操作,登录,注册,获取信息的场景
查看日志发现在每一次操作之前都调用了身份验证的方法,
在这里插入图片描述
这样我们就实现了使用AOP进行统一的用户判断,是不是方便了许多呢?
本篇博客就到这里啦!我们还是下篇博客见~~

在这里插入图片描述

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

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

相关文章

git实战

git实战 第一章 快速入门 1.1 什么是git git是一个分布式的版本控制软件。 软件&#xff0c;类似于QQ、office、dota等安装到电脑上才能使用的工具。版本控制&#xff0c;类似于毕业论文、写文案、视频剪辑等&#xff0c;需要反复修改和保留原历史数据。分布式 - 文件夹拷贝…

RocketMQ教程-(4)-领域模型概述

Apache RocketMQ 是一款典型的分布式架构下的中间件产品&#xff0c;使用异步通信方式和发布订阅的消息传输模型。通信方式和传输模型的具体说明&#xff0c;请参见下文通信方式介绍和消息传输模型介绍。 Apache RocketMQ 产品具备异步通信的优势&#xff0c;系统拓扑简单、上下…

Java-IDEA好用的插件

Lombok&#xff0c;结合一些列注解&#xff0c;帮我们轻松解决重复编写实体类get、set、toString、build、构造方法等麻烦 Chinesepinyin-CodeComp&#xff0c;让界面汉化&#xff0c;使用起来更有亲和力 MyBatisX,点击小鸟图标&#xff0c;轻松再Mapper接口与xml文件之间实…

【算法与数据结构】104、111、LeetCode二叉树的最大/最小深度

文章目录 一、题目二、层序遍历法三、递归法四、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、层序遍历法 思路分析&#xff1a;两道题都可以用层序遍历&#xff08;迭代法&#xff09;来做&#xff0c;遍历完…

帮助中心内容需要囊括什么?(内含案例分享)

给产品制作一个帮助中心&#xff0c;让用户能够通过访问帮助中心查看产品相关内容&#xff0c;尽快了解产品&#xff0c;熟悉操作。不仅仅局限于售后&#xff0c;在售中售前都能够发挥很大的作用&#xff0c;帮助用户全面了解产品&#xff0c;减少销售的工作量&#xff0c;节约…

Zookeeper命令总结

目录 1、常用命令2、ls path3、create xxx创建持久化节点创建临时节点创建持久化序列节点 4、get path5、set path6、delete path7、监听器总结1&#xff09;节点的值变化监听2&#xff09;节点的子节点变化监听&#xff08;路径变化&#xff09;3&#xff09;当某个节点创建或…

最优化方法

一. 图论 1.最小生成树 图的生成树是它的一颗含有其所有顶点的无环连通子图,一 幅加权图的最小生成树(MST)是它的一颗权值(树中的所有边的权值之和) 最小的生成树 • 适用场景&#xff1a;道路规划、通讯网络规划、管道铺设、电线布设等 题目数据 kruskal算法 稀疏图&#x…

oracle单个用户最大连接数限制

项目经理反馈&#xff0c;现场已做了单个用户的最大连接数2000的限制&#xff0c;但数据库还是报无法连接&#xff0c;故障用户的连接数已3800多了。 查看日志报错如下 2023-07-20T13:07:57.79465308:00 Process m000 submission failed with error 20 Process m000 submiss…

HDFS的设计目标和重要特性

HDFS的设计目标和重要特性 设计目标HDFS重要特性主从架构分块存储机制副本机制namespace元数据管理数据块存储 设计目标 硬件故障(Hardware Failure)是常态&#xff0c;HDFS可能有成百上千的服务器组成&#xff0c;每一个组件都有可能出现故障。因此古见检测和自动快速恢复的H…

梯度提升树的基本思想

目录 1. 梯度提升树 VS AdaBoost 2. GradientBoosting回归与分类的实现 2.1 GradientBoosting回归 2.2 GradientBoosting分类 1. 梯度提升树 VS AdaBoost 梯度提升树&#xff08;Gradient Boosting Decision Tree&#xff0c;GBDT&#xff09;是提升法中的代表性算法&#…

帆软报表设计器设置步骤

1、连接工作目录&#xff08;可以是远程服务器&#xff09; 在打开的界面中设置具体的远程地址 一个报表文件可以有多个数据集、但是数据集依附于报表文件的存在&#xff0c;不能跨报表共享。 先补充这么多&#xff0c;有遇到问题再写一点。 &#xff08;完&#xff09;

Cpp 01 — namespace命名空间、C++的输入与输出、缺省参数、函数重载、引用、隐式类型转换

前言&#xff1a;本文章主要用于个人复习&#xff0c;追求简洁&#xff0c;感谢大家的参考、交流和搬运&#xff0c;后续可能会继续修改和完善。 因为是个人复习&#xff0c;会有部分压缩和省略。 一、namespace命名空间 C使用命名空间(namespace)来避免命名冲突。 在定义一个…

STM32CUBUMX配置RS485(中断接收)--保姆级教程

———————————————————————————————————— ⏩ 大家好哇&#xff01;我是小光&#xff0c;嵌入式爱好者&#xff0c;一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子&#xff0c;使用STM32CUBEMX做了很多驱动&#x…

Vue mixin 混入

可以复用的组件&#xff0c;我们一般会抽离&#xff0c;写成公共的模块。 可以复用的方法&#xff0c;我们一般会抽离&#xff0c;写成公共的函数。 那么 在 Vue 中&#xff0c;如果 某几个组件实例 VueComponent 中、或者 整个 Vue 项目中 都存在相同的配置&#xff0c;那就…

firefox笔记-Centos7离线安装firefox

目前&#xff08;2023-03-22 16:41:35&#xff09;Centos7自带的firefox已经很新了是2020年的。主要原因是有个web项目&#xff0c;用2020年的firefox打不开。 发到互联网上是2023-07-24。 报错是js有问题&#xff0c;估计是搞前端的只做了chrome适应&#xff0c;没做firefox…

Spring使用注解进行对象装配(DI)

文章目录 一. 什么是对象装配二. 三种注入方式1. 属性注入2. 构造方法注入3. Setter注入 三. 三种注入方式的优缺点四. 综合练习 通过五大类注解可以更便捷的将对象存储到 Spring 中&#xff0c;同样也可以使用注解将已经储存的对象取出来&#xff0c;直接赋值到注解所在类的一…

ATTO488 NHS ester ,新型亲水性荧光标记物,具有良好的水溶性

陕西新研博美生物科技有限公司MISS.wu小编&#xff08;2023.7月26日&#xff09;为大家整理以下的内容&#xff1a; Atto488-NHS是一种新型亲水性荧光标记物&#xff0c;具有良好的水溶性。这种染料表现得很浓吸收、高荧光量子产率以及优异的热稳定性和光稳定性。因此&#xff…

亚马逊、速卖通,阿里国际等平台测评如何用自养号测评补单

在电商领域&#xff0c;补单是一种常见的推广方式。它能够优化商品销售、留下优质评论、打压竞品和赶走跟卖等&#xff0c;具有很多好处。然而&#xff0c;补单也存在安全性问题&#xff0c;有些卖家找人补单后店铺反而出了问题。因此&#xff0c;了解测评系统是非常重要的的。…

android9-android13 AMS演进初窥

目录 一&#xff1a;概览 WindowManagerService 基本介绍 ActivityManagerService 基本介绍 二&#xff1a;AMS及其关联的WMS中主要组件的类图和对像图 一&#xff1a;android 9中AMS/WMS的类图和对像图 二&#xff1a;android 10中AMS/WMS的类图和对像图 三&#xff1a…

关于应用在Google Play的元数据优化

应用标题中的关键词权重最大&#xff0c;其次是简短描述中的关键词&#xff0c;最后是长描述关键词&#xff0c;了解这些就能够很好的提高应用的可见度&#xff0c;下载量和整体成功率。 1&#xff0c;标题。 Google Play最多允许标题容纳30个字符&#xff0c;关键词的频率和密…