SpringBoot的第二大核心AOP系统梳理

目录

1 事务管理

1.1 事务

1.2 @Transactional注解

1.2.1 rollbackFor

1.2.2 propagation

2 AOP 基础

2.1 AOP入门

2.2 AOP核心概念

3. AOP进阶

3.1 通知类型

3.2 通知顺序

3.3 切入点表达式

execution切入点表达式

@annotion注解

3.4 连接点

1 事务管理

1.1 事务

事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功,要么同时失败。

事务的目标:保证操作前后,数据的一致性。

事务的操作主要有三步:

  1. 开启事务(一组操作开始前,开启事务):start transaction / begin ;

  2. 提交事务(这组操作全部成功后,提交事务):commit ;

  3. 回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;

1.2 @Transactional注解

在当前方法执行之前来开启事务,方法执行完毕后提交事务。如果在方法执行过程中出现异常,就会进行事务的回滚操作。

我们一般会在service层控制事务,因为一个业务功能可能会包含多个数据访问操作。在sevice层控制事务,我们就可以将多个数据访问操作控制在一个事务范围内。

@Transactional注解书写位置:

  • 方法  (当前方法交给spring进行事务管理)

  • 类  (当前类中所有的方法都交由spring进行事务管理)

  • 接口  (接口下所有的实现类当中所有的方法都交给spring 进行事务管理)

说明:在application.yml配置文件中开启事务管理日志,可以在console看到和事务相关的日志信息

@Transactional注解的两个常见属性:

  1. 异常回滚的属性:rollbackFor

  2. 事务传播行为:propagation

1.2.1 rollbackFor

默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务。  

如果需要指定出现某种异常时回滚事务,需要配置@Transactional注解中的rollbackFor属性。

@Transactional(rollbackFor=Exception.class)
1.2.2 propagation

propagation作用:配置事务的传播行为

在A方法运行的时候,首先会开启一个事务,在A方法当中又调用了B方法, B方法自身也是事务,那么B方法在运行的时候,到底是加入到A方法的事务当中来,还是B方法在运行的时候新建一个事务?

解决方案:给B方法加上注解

@Transactional(propagation = Propagation.REQUIRES_NEW)//不论A是否有事务,都新建事务
属性值含义
REQUIRED【默认值】B方法加入到A的事务中。
REQUIRES_NEW为B创建新事务。即使A运行异常需要回滚,也不影响B的事务提交。

2 AOP 基础

2.1 AOP入门

AOP(Aspect Oriented Programming,面向切面编程)就是面向特定方法编程,是一种编程思想。  

AOP的作用:在程序运行期间在不修改源代码的基础上对已有方法进行功能增强(无侵入性: 解耦)  

AOP的优势:

  1. 减少重复代码

  2. 提高开发效率

  3. 维护方便

实现步骤:

  1. 导入依赖:在pom.xml中导入AOP的依赖

  2. 编写AOP程序:给特定方法增强功能

pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Component//标注一个类为Spring容器的Bean
@Aspect //当前类为切面类
@Slf4j//日志框架
public class TimeAspect {@Around("execution(* com.itheima.service.*.*(..))") public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {//记录方法执行开始时间long begin = System.currentTimeMillis();//执行原始方法Object result = pjp.proceed();//记录方法执行结束时间long end = System.currentTimeMillis();//计算方法执行耗时log.info(pjp.getSignature()+"执行耗时: {}毫秒",end-begin);return result;}
}

AOP常见的应用场景:

  • 统计各个业务层方法的执行耗时

  • 记录系统的操作日志

  • 权限控制

  • 事务管理:我们前面所讲解的Spring事务管理,底层其实也是通过AOP来实现的,只要添加@Transactional注解之后,AOP程序自动会在原始方法运行前先来开启事务,在原始方法运行完毕之后提交或回滚事务

2.2 AOP核心概念

1. 连接点:JoinPoint所有可以被AOP控制的方法

2. 通知:Advice,控制连接点的方法,比如上面的recordTime()方法

3. 切入点:PointCut,execution里的方法,通知仅会在切入点方法执行时被应用

假如切入点表达式改为DeptServiceImpl.list(),就代表只有list()方法运行时才会应用通知。  

4. 切面:Aspect,通知+切入点

通过切面能够描述当前AOP程序针对哪个原始方法(连接点),在什么条件下(切入点表达式)执行什么样的操作(通知)。

切面所在的类,我们一般称为切面类(被@Aspect注解标识的类),比如上面的TimeAspect类。

 5. 目标对象:Target,连接点方法所属的类

Spring的AOP底层是基于动态代理实现的,即在程序运行时,会自动为目标对象生成对应的代理对象。在代理对象中按照通知目标对象中的原始方法进行功能增强。然后将代理对象注入到Controller层。  

3. AOP进阶

3.1 通知类型

  • @Around:环绕通知,通知方法在目标方法前、后都被执行。

  • @Before:前置通知,通知方法在目标方法前被执行

  • @After :后置通知,通知方法在目标方法后被执行,无论是否有异常都会执行

  • @AfterReturning : 返回后通知,通知方法在目标方法正常执行后被执行

  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

在使用@Around环绕通知时的注意事项:

  1. 原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了

  2. @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行

  3. @Around环绕通知方法的返回值必须指定为Object。来接收原始方法的返回值,否则原始方法执行完毕,是获取不到返回值的。

@PointCut注解:作用是将公共的切入点表达式抽取出来,需要用到时引用该切入点表达式即可。   

@Slf4j
@Component
@Aspect
public class MyAspect1 {//切入点方法(公共的切入点表达式)@Pointcut("execution(* com.itheima.service.*.*(..))")private void pt(){}//前置通知(引用切入点)@Before("pt()")public void before(JoinPoint joinPoint){log.info("before ...");}//环绕通知@Around("pt()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {log.info("around before ...");//调用目标对象的原始方法执行Object result = proceedingJoinPoint.proceed();//如果原始方法在执行时发生异常,则后续代码不在执行log.info("around after ...");return result;}
}

注意:当切入点方法使用private修饰时,仅能在当前切面类中引用该表达式, 当外部其他切面类也要引用当前类中的切入点表达式时,需要把private改为public,而在引用的时候,具体的语法为:全类名.方法名()。

3.2 通知顺序

定义了多个切面类,而多个切面类中多个切入点都匹配到了同一个目标方法。此时当目标方法在运行的时候,这多个切面类当中的这些通知方法都会运行。哪个先运行,哪个后运行?

在不同切面类中,默认按照切面类的类名字母排序:

  • 目标方法@Before方法:字母排名靠前的执行

  • 目标方法@After方法:字母排名靠前的执行

@Order注解:控制通知的执行顺序

@Slf4j
@Component
@Aspect
@Order(2)  //切面类的执行顺序(前置通知:数字越小先执行; 后置通知:数字越小越后执行)
public class MyAspect2 {//通知
}

3.3 切入点表达式

作用:主要用来决定项目中的哪些方法需要加入通知

execution切入点表达式

示例:

execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))
execution(* com..DeptServiceImpl.delete(java.lang.Integer))  
execution(* com..*.*(..))
//匹配DeptServiceImpl类中以find开头的方法
execution(* com.itheima.service.impl.DeptServiceImpl.find*(..))

 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性

@annotion注解

 新建一个注解(跟新建类的方式一样);

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}

 然后在目标方法上添加注解@MyLog,表示该方法被通知方法控制;

最后在切面类中的通知方法添加@annotation注解,括号里的参数为MyLog的全名。

@Slf4j
@Component
@Aspect
public class MyAspect6 {//前置通知@Before("@annotation(com.itheima.anno.MyLog)")public void before(){log.info("MyAspect6 -> before ...");}
}

当一个新的方法需要被该通知方法控制时,在新方法上添加注解@MyLog即可。

3.4 连接点

在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。

  • 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint类型

  • 对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型

@Slf4j
@Component
@Aspect
public class MyAspect7 {@Pointcut("@annotation(com.itheima.anno.MyLog)")private void pt(){}//前置通知@Before("pt()")public void before(JoinPoint joinPoint){log.info(joinPoint.getSignature().getName() + " MyAspect7 -> before ...");}//后置通知@Before("pt()")public void after(JoinPoint joinPoint){log.info(joinPoint.getSignature().getName() + " MyAspect7 -> after ...");}//环绕通知@Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable {//获取目标类名String name = pjp.getTarget().getClass().getName();log.info("目标类名:{}",name);//目标方法名String methodName = pjp.getSignature().getName();log.info("目标方法名:{}",methodName);//获取方法执行时需要的参数Object[] args = pjp.getArgs();log.info("目标方法参数:{}", Arrays.toString(args));//执行原始方法Object returnValue = pjp.proceed();return returnValue;}
}

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

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

相关文章

云计算与 openstack

文章目录 一、 虚拟化二、云计算2.1 IT系统架构的发展2.2 云计算2.3 云计算的服务类型 三、Openstack3.1 OpenStack核心组件 一、 虚拟化 虚拟化使得在一台物理的服务器上可以跑多台虚拟机&#xff0c;虚拟机共享物理机的 CPU、内存、IO 硬件资源&#xff0c;但逻辑上虚拟机之…

组装电脑(使用老机箱)

昨天同事拿来一台联想 ThinkCentre M6210t的台式机&#xff0c;说计算机实在是太慢了&#xff0c;在只保留主机箱想升级一下。   她拿来了配件&#xff0c;有电源、主板、CPU、CPU风扇、内存条、机箱风扇、硬盘&#xff1a;   主板&#xff1a;华硕 Prime H610M-K D4&#…

element-ui表格全选

项目场景&#xff1a; 根据项目需求&#xff0c;要求在表格外加【全选】复选框&#xff0c;切换分页也需将每一行都勾选上 实现方式&#xff1a; 借用element-ui文档的这几个方法和属性 <el-checkboxv-model"checkAll"change"handleCheckAllChange"&g…

【计算机网络】——物理层(图文并茂)

物理层 一.物理层概述1.物理层要实现的功能2.物理层接口特征1.机械特性2.电气特性3.功能特性4.过程特性 二.物理层下面的传输媒体1.传输媒体的分类2.导向型传输媒体1.同轴电缆2.双绞线3.光纤 3.非导向型传输媒体1.无线电波2.微波3.红外线4.激光5.可见光 三.传输方式1.串行传输与…

自动化桌面整理新时代:Llama 3驱动的智能文件管理系统

在信息爆炸的时代,个人和企业用户的电脑桌面常常被海量文件占据,导致查找特定文件如同大海捞针。为了解决这一痛点,Llama 3应运而生——一个集成了先进多模态AI技术的智能文件管家,旨在将杂乱无章的文件世界变得井然有序。本文将深入探讨Llama 3如何利用其创新功能,不仅自…

研发效能DevOps: Ubuntu 部署 JFrog 制品库

目录 一、实验 1.环境 2.Ubuntu 部署 JFrog 制品库 3.Ubuntu 部署 postgresql数据库 4.Ubuntu 部署 Xray 5. 使用JFrog 增删项目 二、问题 1.Ubuntu 如何通过apt方式部署 JFrog 制品库 2.Ubuntu 如何通过docker方式部署 JFrog 制品库 3.安装jdk报错 4.安装JFrog Ar…

javascript DOM 属性详解:读取、修改、移除

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、读取…

动态路由协议实验——RIP

动态路由协议实验——RIP 什么是RIP ​ RIP(Routing Information Protocol,路由信息协议&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;是一种动态路由选择协议&#xff0c;用于自治系统&#xff08;AS&#xff09;内的路由信息的传递。RIP协议基于…

实时数据传输:Django 与 MQTT 的完美结合

文章目录 准备工作创建 Django 项目与应用设置 MQTT 服务器编写 Django 视图编写前端模板发布 MQTT 消息运行 Django 项目 在当今互联网应用中&#xff0c;实时数据传输已经成为许多项目的核心需求。无论是社交媒体平台、在线游戏、金融交易还是物联网设备&#xff0c;都需要及…

Python—面向对象小解(3)

一、多态 多态指的是一类事物的多中形态 相同的方法&#xff0c;产生不同的执行结果 运算符 * 的多态 int int 加法计算 str str 字符串拼接 list list 列表的数据合并 在python中可以使用类实现一个多态效果 在python中使用重写的方式实现多态 &#xff08;1&#xff09;定…

飞腾D2000+FPGA云终端,实现从硬件、操作系统到应用的完全国产、自主、可控

飞腾云终端基于国产化飞腾高性能8核D2000处理器平台的国产自主可控解决方案&#xff0c;搭载昆仑国产化固件,支持UOS、银河麒麟等国产操作系统&#xff0c;满足国产化信息安全运算的需求&#xff0c;实现从硬件、操作系统到应用的完全国产、自主、可控&#xff0c;是国产信息安…

WireShark抓包软件的使用 上海商学院 计算机网络 实验作业3

实验目的 &#xff08;1&#xff09;熟悉wireShark软件操作界面和操作步骤&#xff1b; &#xff08;2&#xff09;学会捕获过滤器的设置方法&#xff1b; &#xff08;3&#xff09;学会显示过滤器的设置方法&#xff1b; &#xff08;4&#xff09;学会使用捕获报文的统计…

20231911 2023-2024-2 《网络攻防实践》实践十一报告

实践内容 &#xff08;1&#xff09;web浏览器渗透攻击 任务&#xff1a;使用攻击机和Windows靶机进行浏览器渗透攻击实验&#xff0c;体验网页木马构造及实施浏览器攻击的实际过程。 实验步骤&#xff1a; ①选择使用Metasploit中的MS06-014渗透攻击模块②选择PAYLOAD为任意…

Linux基本命令的使用(mkdir)

一、Linux必备命令之mkdir • mkdir命令主要用于创建目录 • 语法: mkdir [选项] 目录名称 若指定目录不存在则创建目录&#xff1b; 选项&#xff1a; -p&#xff0c;--parents 需要时创建目录的上层目录&#xff0c;若这些 目录已存在也不当作错误处理 二、Linux必备命令之…

java基础-chapter15(io流)

io流&#xff1a;存储和读取数据的解决方案 I:input O:output io流的作用&#xff1a;用于读写数据&#xff08;本地文件,网络&#xff09; io流按照流向可以分为&#xff1a; 输出流&#xff1a;程序->文件 输入流&#xff1a;文件->程序 io流按照操作文件…

nginx的安装002

之前001讲述了nginxyum安装现在讲一下nginx如何本地离线安装 操作系统&#xff1a; CentOS Stream 9 操作步骤&#xff1a; 首先访问nginx官网&#xff0c;下载。 用wget命令下载&#xff0c; [rootlocalhost ~]# wget -c https://nginx.org/download/nginx-1.26.0.tar.gz …

python基础(习题、资料)

免费提取资料&#xff1a; 练习、资料免费提取。持续更新迅雷云盘https://pan.xunlei.com/s/VNz6kH1EXQtK8j-wwwz_c0k8A1?pwdrj2x# 本文为Python的进阶知识合辑&#xff0c;包括列表&#xff08;List&#xff09;、元组&#xff08;Tuple&#xff09;、字典&#xff08;Dic…

四川景源畅信:抖音开店怎么做好运营?

在数字化时代的浪潮中&#xff0c;抖音作为一个流量巨大的社交平台&#xff0c;为许多商家提供了展示和销售产品的新舞台。但在这个充满竞争的平台上&#xff0c;如何做好店铺运营&#xff0c;吸引并留住顾客&#xff0c;成为了许多商家面临的挑战。接下来的内容将围绕如何在抖…

程序启动端口占用问题 cause: Address already in use: bind

1、winr打开cmd窗口 2、找到占用端口的进程号 netstat -aon|findstr "20792" 3、终止进程 taskkill /T /F /PID 18208

实验---DC-AC逆变器(1)---EG8010+NSI6602驱动IGBT实验

一、设计电路 1.LCC 主回路模块原理图 1.1 电源部分 这个电源部分电路图是一个简单而有效的DC-DC转换器设计&#xff0c;包含输入保护和滤波、电源模块、以及输出滤波和稳定。 a. 输入电源部分 输入电源 (E12V): 电路从E12V端子接收12V的直流电源。这是整个电路的输入电源。…