关于SpringBoot中AOP的深入理解

一,AOP入门

1、AOP概述

AOP,Aspect Oriented Programming面向切面编程思想,是对OOP(面向对象)进行的补充

OOP是纵向继承技术,可以将程序中一段连续的代码进行封装

AOP是横向抽取技术,可以将程序中四个位置(核心概念之前、返回值之后、catch、finally)的非核心业务代码封装到一个类中(切面),在将切面中的功能套到(织入)目标对象具体的方法上

AOP在不改变源码的基础上实现功能的增强

AOP的重要应用是日志和事务等

2、AOP的专业术语

代理对象:代理目标对象的对象

目标对象:被代理的对象

横切关注点:指从核心代码中抽取的非核心业务代码,例: 添加日志功能

切面:封装非核心业务代码(横切关注点)的类

通知:切面中封装横切关注点的方法为通知方法,例: 把日志功能封装的方法

切入点:切面中通知作用于目标对象中方法的位置(通知之后)

切入点表达式:定位切入点的一种表达式

切入点是一个用于筛选连接点的表达式或者规则。它的主要作用是从众多的连接点中选择出符合特定条件的那些连接点。它就像一个过滤器,决定了 AOP 的横切逻辑应该应用到哪些具体的位置。只有符合这个表达式的连接点才会被性能监控这个 AOP 功能所增强

并且同一个连接点可能会被多个不同的切入点选中,也可能一个都不被选中。

连接点:在目标对象中抽取横切关注点的位置(方法)(通知之前)

连接点是在程序执行过程中能够插入切面(Aspect)的点。在 Spring AOP 中,这些点通常是方法的调用。

在准备使用AOP技术对哪个方法添加额外功能的方法就是一个连接点,这些点在 Spring AOP 中主要是指方法的调用、方法的执行、异常的抛出等位置。通常指的方法名

在使用AOP技术之前要添加额外功能的方法叫做连接点,在创建了切面类后,准备把切面类插入到哪里执行的位置也就是哪个方法(经过切入点表达式进行过滤后要使用的方法)叫做切入点。

可以说就是同一个方法,只是因为时间上的不同,分别给了不同的命名。

连接点(Join Point)和切入点(Pointcut)是不同的概念。
定义角度
连接点

​ 在 Spring AOP 中,连接点主要是基于方法调用的。在底层,Spring AOP 使用动态代理或者字节码增强技术来拦截这些方法调用,从而实现 AOP 功能。从开发者的角度看,只要知道在方法调用的这个时刻,AOP 机制就可以介入。

​ 连接点是在程序执行流程中,能够被切面(Aspect)插入额外逻辑的特定位置。从本质上讲,它是程序运行过程中的一个点,这些点在 Spring AOP 中主要是指方法的调用、方法的执行、异常的抛出等位置。例如,在一个 Java 的 Web 应用中,每次调用一个 Servlet 的doGet或doPost方法时,这个方法调用的位置就是一个连接点。连接点是一个比较宽泛的概念,它代表了所有可能被 AOP 增强的位置。
切入点

​ 切入点表达式通常使用 AspectJ 的语法

​ 切入点是一个用于筛选连接点的表达式或者规则。它的主要作用是从众多的连接点中选择出符合特定条件的那些连接点。例如,我们可以定义一个切入点表达式,用来选择某个特定包下所有以 “add” 开头的方法调用作为连接点,那么这个表达式所确定的这些特定的方法调用位置就是切入点所筛选出来的连接点。
数量角度
连接点
​ 连接点的数量通常是由程序的结构和执行流程决定的。一个复杂的应用程序可能有大量的连接点。例如,一个包含多个业务层、持久层和控制层的大型企业级应用,其中每个层都有许多方法,这些方法的调用位置都是连接点,数量可能会有成百上千个。
切入点
​ 切入点的数量是由开发者定义的。可以根据业务需求和功能模块等因素来定义不同的切入点。例如,可能为日志记录功能定义一个切入点,为事务管理功能定义另一个切入点。并且同一个连接点可能会被多个不同的切入点选中,也可能一个都不被选中。
功能角度
连接点
​ 连接点只是提供了一个可以插入切面逻辑的机会,它本身并没有对 AOP 增强的范围进行任何限制。例如,在一个方法调用这个连接点上,如果没有切入点的筛选,我们不知道是否要对这个方法调用进行日志记录、事务管理或者其他 AOP 操作。
切入点
​ 切入点则明确了哪些连接点需要进行 AOP 增强。它就像一个过滤器,决定了 AOP 的横切逻辑应该应用到哪些具体的位置。例如,我们通过一个切入点表达式确定了只对某个特定模块下的方法调用进行性能监控,那么只有符合这个表达式的连接点才会被性能监控这个 AOP 功能所增强。

二、基于注解的AOP的实现

1、实现步骤

a>导入aop的场景启动器

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

b>创建切面,并将目标对象和切面类的对象交给IOC容器管理

c>使用**@Aspect注解标记切面组件,并加上@Component**把切面类交给IOC作为一个bean使用

d>在配置类上使用**@EnableAspectJAutoProxy**注解开启AspectJ的自动代理功能,注意,在SpringBoot的环境中可以省略不写

2、通知

前置通知:使用@Before注解标记切面中方法,将其标记为前置通知的方法,在目标对象方法执行之前执行

后置通知:使用@After注解标记切面中的方法,将其标记为后置通知的方法,在目标对象方法的finally中执行

后置通知也叫做最终通知,不管目标对象中是否有异常都会执行

返回通知:使用@AfterReturning注解标记切面中的方法,将其标记为返回通知的方法,在目标对象方法的返回值之后执行

异常通知:使用@AfterThrowing注解标记切面中的方法,将其标记为异常通知的方法,在目标对象方法的catch中执行

环绕通知:使用@Around注解标记切面中的方法,将其标记为环绕通知的方法,相当于以上四种通知结合使用

注意:

1、环绕通知的方法的形参位置必须设置ProceedingJoinPoint类型的形参,通过joinPoint.proceed()表示目标对象方法的执行

2、环绕通知的方法必须设置Object类型的返回值,将joinPoint.proceed()方法的返回值进行返回,joinPoint.proceed()方法的返回值就是目标对象方法的返回值;若环绕通知没有返回值则直接抛出异常AopInvocationException

@Around("pointCut()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) {

 Object result = null;
 try {
     System.out.println("环绕通知(前置)");
     //调用目标对象的方法
     result = joinPoint.proceed();
     System.out.println("环绕通知(返回)");
 } catch (Throwable e) {
     System.out.println("环绕通知(异常)");
     throw new RuntimeException(e);
 } finally {
     System.out.println("环绕通知(后置)");
 }
 return result;
}

3、切入点表达式

@Before(“execution(public int com.yuan.aop.CalcImpl.add(int, int))”)

* 包名.类名.方法名(参数类型) —>(* yuan.*.*(..))

任意的访问修饰符和返回值类型使用* ,这里用一个* 代替类似于 public int 的访问修饰符和返回值

类中任意的方法使用*

包下任意的类使用*

包名和类名以指定的内容开始使用xxx*

包名和类名以指定的内容结束使用*xxx

任意的参数类型使用…

  • 切入点表达式通常使用 AspectJ 的语法。例如,execution(* com.example.service.UserService.update*(..))就是一个切入点表达式。其中execution是关键字,表示执行方法的连接点。*在返回值类型位置表示任意返回值类型,com.example.service.UserService.update*(..)表示com.example.service.UserService类中以update开头的所有方法,(..)表示方法可以有任意参数。

4、公共的切入点表达式

作用:把切入点表达式作为一个过滤器,对要插入额外功能的连接点方法进行筛选,然后插入切面类

a>声明公共的切入点表达式

//声明公共的切入点表达式
@Pointcut("execution(* com.yuan.aop.*.*(..))")
public void pointCut(){}

b>使用公共的切入点表达式

@Before("pointCut()")
public void beforeMethod() {
    System.out.println("前置通知");
}

5、获取连接点信息

a>获取连接点所对应方法的方法名和参数

在通知方法的形参位置设置JoinPoint类型的形参,其中封装了连接点相关信息

//获取连接点所对应方法的方法名
String methodName = joinPoint.getSignature().getName();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();

b>在返回通知中获取目标对象方法的返回值

在通知方法的形参位置设置一个Object类型的形参,使用@AfterReturning注解中的returning属性,将该参数设置为接收目标对象方法的返回值的参数

@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
    String methodName = joinPoint.getSignature().getName();
    System.out.println("返回通知,方法名:"+methodName+",结果:"+result);
}

c>在异常通知中获取目标对象方法出现的异常

在通知方法的形参位置设置一个Exception或Throwable类型的形参,使用@AfterThrowing注解中的throwing属性,将该参数设置为接收目标对象方法出现的异常的参数

@AfterThrowing(value = "pointCut()", throwing = "e")
public void afterThrowingMethod(JoinPoint joinPoint, Throwable e) {
    String methodName = joinPoint.getSignature().getName();
    System.out.println("异常通知,方法名:"+methodName+",异常:"+e);
}

6、切面的优先级

使用@Order注解标记切面,设置优先级,通过value属性设置一个整数,值越小优先级越高,

@Component
@Aspect  //标记为一个切面组件
@Order(1)  //优先级,默认优先级都是Integer的最大值,所以你无论写多大,都会比Integer的最大值小,都会先执行设置优先级的切面类
public class ValidateAspect {
        @Before("com.yuan.aop.LoggerAspect.poinCut()")
        public void before(JoinPoint joinPoint){
                System.out.println("ValidateAspect------->前置通知");
        }
}

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

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

相关文章

【字符串匹配算法——BF算法】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 BF算法介绍及过程演示代码实现过程下节预告KMP算法利用next数组存储子串中j回退的位置&#xff08;…

单幅图像合成 360° 3D 场景的新方法:PanoDreamer,可同时生成全景图像和相应的深度信息。

论文介绍了一种从单幅图像合成 360 3D 场景的新方法。该方法以连贯的方式生成全景图及其相应的深度&#xff0c;解决了现有最先进方法&#xff08;如 LucidDreamer 和 WonderJourney 的局限性。这些方法按照生成轨迹依次添加细节&#xff0c;通常在循环回输入图像时导致可见的接…

【蓝桥杯】46195.水仙花数

水仙花数 问题描述 打印所有100至999之间的水仙花数。所谓水仙花数是指满足其各位数字立方和为该数字本身的整数&#xff0c;例如 153135333。 样例输入 无 样例输出 153 370 371 407解题思路 遍历100到999之间的所有整数。对每个整数&#xff0c;计算其各位数字的立方和…

#思科模拟器通过服务配置保障无线网络安全Radius

演示拓扑图&#xff1a; 搭建拓扑时要注意&#xff1a; 只能连接它的Ethernet接口&#xff0c;不然会不通 MAC地址绑定 要求 &#xff1a;通过配置MAC地址过滤禁止非内部员工连接WiFi 打开无线路由器GUI界面&#xff0c;点开下图页面&#xff0c;配置路由器无线网络MAC地址过…

cpolar使用步骤

功能&#xff1a;内网穿透 下载地址&#xff1a;cpolar - secure introspectable tunnels to localhost 1 找到安装目录 2 进入命令行 目录处输入 cmd 3 验证 authtoken 不同用户 验证码不同。 注册后可以使用 cpolar.exe authtoken MzBlNzMwODktZjA3Yi00ZjJlLWJiMzQtNWU…

【排序算法】——插入排序

目录 前言 简介 基本思想 1.直接插入排序 2.希尔排序 代码实现 1.直接插入排序 2.希尔排序 总结 1.时空复杂度 2.稳定性 尾声 前言 排序(Sorting) 是计算机程序设计中的一种重要操作&#xff0c;它的功能是将一个数据元素&#xff08;或记录&#xff09;的任意序列&…

MySQL学习之DDL操作

目录 数据库的操作 创建 查看 选择 删除 修改 数据类型 表的创建 表的修改 表的约束 主键 PRIMARY KEY 唯一性约束 UNIQUE 非空约束 NOT NULL 外键约束 约束小结 索引 索引分类 常规索引 主键索引 唯一索引 外键索引 优点 缺点 视图 创建 删除 修改…

四、网络层:数据平面,《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》

文章目录 零、导论0.1 网络层服务0.2 网络层的关键功能0.3 网络层&#xff1a;数据平面、控制平面0.4 传统方式&#xff1a;每一路由器&#xff08;Per-router&#xff09;控制平面0.5 传统方式&#xff1a;路由和转发的相互作用0.6 SDN方式&#xff1a;逻辑集中的控制平面0.7 …

Java每日一题(1)

给定n个数a1,a2,...an,求它们两两相乘再相加的和。 即&#xff1a;Sa1*a2a1*a3...a1*ana2*a3...an-2*an-1an-2*anan-1*an 第一行输入的包含一个整数n。 第二行输入包含n个整数a1,a2,...an。 样例输入 4 1 3 6 9 样例输出 117 答案 import java.util.Scanner; // 1:无…

(2024.12自用存档)Ubuntu20.04——DynSLAM运行命令

前面忘记记录了&#xff0c;大概记一下后面 看了很多大佬的文章&#xff08;感谢&#xff01;&#xff09;&#xff0c;包括但不限于以下参考文章&#xff1a; Ubuntu16.04编译dynslam总结-CSDN博客 ubuntu14.04 CUDA8.0 DynSLAM编译与运行-CSDN博客 【视觉SLAM十四讲】Pa…

【阅读笔记】Android AMS forcestop停止应用

根据这篇文章作的笔记 基于Android 12的force-stop流程分析_android forcestop-CSDN博客 在AMS中&#xff0c;停止指定的应用是一个常用的功能&#xff0c;在代码里可以看到 Override 6806 public void forceStopPackage(final String packageName, int userId) { 6807 …

uniapp连接蓝牙操作(蓝牙设备地锁)

介绍&#xff1a; 本文采用uni-app框架来创建一个简单的用户界面&#xff0c;用于搜索、连接和发送命令给蓝牙设备。 1.打开蓝牙适配器 function openBluetooth() {uni.openBluetoothAdapter({success() {uni.offBluetoothDeviceFound();// 监听新设备发现事件uni.onBlueto…

《拉依达的嵌入式\驱动面试宝典》—前言目录篇

《拉依达的嵌入式\驱动面试宝典》—前言&目录篇 你好&#xff0c;我是拉依达。 感谢所有阅读关注我的同学支持&#xff0c;目前博客累计阅读 27w&#xff0c;关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析&#xff08;持续更新&#xff09;-CSDN博客》已经是 Lin…

【博弈模型】古诺模型、stackelberg博弈模型、伯特兰德模型、价格领导模型

博弈模型 1、古诺模型&#xff08;cournot&#xff09;&#xff08;1&#xff09;假设&#xff08;2&#xff09;行为分析&#xff08;3&#xff09;经济后果&#xff08;4&#xff09;例题 2、stackelberg博弈模型&#xff08;产量领导模型&#xff09;&#xff08;1&#xff…

如何利用Python爬虫获得1688商品详情

在这个信息爆炸的时代&#xff0c;数据就像是一块块美味的奶酪&#xff0c;而爬虫就是我们手中的瑞士军刀。今天&#xff0c;我要带你一起潜入1688这个巨大的奶酪洞穴&#xff0c;用Python爬虫捞起那些香气四溢的商品详情。别担心&#xff0c;我们的工具箱里有各种各样的工具&a…

blender 制作莫比乌斯带

创建 Curve -> Cycle 在 Edit 模式下&#xff0c;选择&#xff1a; 选中两个点&#xff0c;按 delete 删除 Segment 如下选中&#xff1a; 选中最上面的点&#xff0c;然后按 E 将它拖到右边的点上。 按 R 旋转 90 度。 依次调整参数&#xff1a; 回到 Object 模式下&#x…

《云原生安全攻防》-- K8s安全框架:认证、鉴权与准入控制

从本节课程开始&#xff0c;我们将来介绍K8s安全框架&#xff0c;这是保障K8s集群安全比较关键的安全机制。接下来&#xff0c;让我们一起来探索K8s安全框架的运行机制。 在这个课程中&#xff0c;我们将学习以下内容&#xff1a; K8s安全框架&#xff1a;由认证、鉴权和准入控…

研华运动控制卡 (如PCI1245)单轴编辑路

问题描述: 单轴如何编辑路径&#xff1f; n 问题分析及处理办法– 步骤 在utility软件中&#xff0c;编辑路径和运行路径只能在多轴运动这个界面&#xff0c;而且&#xff0c;使用函数来加载路径Acm_GpLoadPath&#xff0c;也是需要多个轴 ​ 如果只运行一个轴&#xff0c;需…

LM芯片学习

1、LM7805稳压器 https://zhuanlan.zhihu.com/p/626577102?utm_campaignshareopn&utm_mediumsocial&utm_psn1852815231102873600&utm_sourcewechat_sessionhttps://zhuanlan.zhihu.com/p/626577102?utm_campaignshareopn&utm_mediumsocial&utm_psn18528…

ChromeOS 131 版本更新

ChromeOS 131 版本更新 1. ChromeOS Flex 自动注册 在 ChromeOS 131 中&#xff0c;ChromeOS Flex 的自动注册功能现已允许大规模部署 ChromeOS Flex 设备。与 ChromeOS 零接触注册类似&#xff0c;自动注册将通过组织管理员创建的注册令牌嵌入到 ChromeOS Flex 镜像中。这将…