【Spring】超详细讲解AOP(面向切面编程)

文章目录

  • 1. 前言
  • 2. 什么是AOP
  • 3. AOP快速入门
  • 4. AOP的核心概念
  • 5. 切点表达式
  • 6. 切点函数
  • 7. 通知
  • 8. 总结

1. 前言

本文围绕AOP进行讲解,AOP可以做什么,涉及到了哪些注解,以及各个注解运行的时机,以及@Around相较于其它注解有什么不同,并且如果要执行目标方法需要怎么做

2. 什么是AOP

Spring的AOP(面向切面编程)是Spring框架的一个重要特性,它允许开发人员在应用程序中通过定义切面来实现横切关注点的功能,如日志记录、性能监控、事务管理等。AOP通过将这些关注点从业务逻辑中抽离出来,使得代码更加模块化、可维护和可重用。

SpringAOP就是批量对Spring容器中bean的方法做增强,并且这种增强不会与原来方法中的代码耦合

3. AOP快速入门

目标:要求service包下所有的类中的方法调用前输出: “方法被调用了”

在学AOP前,大家可能会在每个方法内添加一个输出语句. 但如果类很多,类中的方法也很多,添加起来也很麻烦,而且如果后续要进行修改,也很麻烦

  1. 首先要引入相关依赖:
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.29</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>
</dependencies>    
  1. 把相关bean放到Spring容器中

可以使用注解@ComponentScan(basePackages = "com.example"),也可以在xml配置文件中,使用<context:component-scanbase-package="com.example"></context:component-scan>

在这里插入图片描述

因为我的代码结构是这样的,所以是com.example.

  1. 实现AOP

实现AOP可以使用注解,也可以使用xml配置文件. 因为是入门,所以先认识一下注解实现AOP的方式

①开启AOP注解支持

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

②创建切换类

其实就是普通的类,加上@Componentx @Aspect这两个注解而已

使用使用@Pointcut注解来指定要被强的方法
使用@Before注解来给我们的增湿代码所在的方法进行标识,并且指定了增强代码是在被增强方法执行之前执行
的。

示例:

@Component
@Aspect
public class MyAspect {@Pointcut("execution(* com.example.service.*.*(..))")public void point(){}@Before("point()")public void methodBefore(){System.out.println("方法被调用了");}
}
@Pointcut("execution(* com.example.service.*.*(..))")

这段代码:是指 对com.example的service包下类的所有方法进行增强

 @Before("point()")public void methodBefore(){System.out.println("方法被调用了");}

@Before("point()")是指选中point()这个切点表达式的方法进行增强,增强的内容就是方法中的代码

UserService:

@Service
public class UserService {public void update(){System.out.println("执行了UserService的update方法");}
}

准备工作完成,进行测试.
在这里插入图片描述
可以看到在执行UserService的update()方法前,输出了"方法被调用了"

4. AOP的核心概念

  • Joinpoint (连接点): 所谓连接点是指那些可以被增强到的点。在spring中,这些点指的是方法,因为spring
    只支持方法类型的连接点
  • ⭐Pointcut (切入点) : 所谓切入点是指被增强的连接点(方法)
  • Advice (通知/ 增强) : 所谓通知是指具体增强的代码
  • Target (目标对象): 被增强的对象就是目标对象
  • Aspect (切面) : 是切入点和通知(引介) 的结合
  • Proxy (代理) : 一个类被 AOP 增强后,就产生一个结果代理类

5. 切点表达式

切点表达式用来表示要对哪些方法进行增强

写法: execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略,大部分情况下可以省略
  • 返回值类型、包名、类名、方法名可以使用星号* 代表任意包
  • 名与类名之间一个点.代表当前包下的类,两个点..表示当前包及其子包下的类
  • 参数列表可以使用两个点..表示任意个数,任意类型的参数列表

如快速入门中的切点表达式:

execution(* com.example.service.*.*(..))

该切点表达式就是 对com.example的service包下类的所有方法进行增强,

6. 切点函数

我们也可以在要增强的方法上加上注解。然后使用@annotation来表示对加了什么注解的方法进行增强。

示例:

首先自定义一个注解,在创建类时选择Annotation
在这里插入图片描述

public @interface MyComment{}

注意此时是不能直接用,我们需要添加几个注解
不知道添加什么也很好办,可以直接写一个注解,点击看源码
在这里插入图片描述

  • @Retention(RetentionPolicy.RUNTIME): 表示注解可以保持到什么时期,RUNTIME就是运行时
  • @Target({ElementType.METHOD}): 表示此注解可以添加到哪些东西方法,METHOD就是方法
    直接将注解添加到我们自定义的注解上即可

在这里插入图片描述
使用自定义注解,直接在相应的方法中添加即可:在这里插入图片描述
此时的切点就不能像之前那样写了,需要使用@annotation注解,并加上自定义注解的全类名
在这里插入图片描述
此时运行代码同样可以看到userService中的方法被增强了.
在这里插入图片描述
其实这种方式的AOP增强比使用切点表达式灵活多了.

7. 通知

SpingAOP的通知共有五种:

  • @Before: 前置通知在方法执行前执行
  • @AfterReturning: 返回后通知,在目标方法执行后执行,如果出现异常不会执行
  • @After: 后置通知,在目标方法返回结果之后执行,无论是否出现异常都会执行
  • @AfterThrowing: 异常通知,在目标方法抛出异常后执行
  • @Around: 环绕通知,围绕着方法执行

@Before,@AfterReturning和@After方法使用起来很简单,只需要知道加了这些注解的方法是在什么时候增强的即可

示例:

@Component
@Aspect
public class MyAspect {@Pointcut("@annotation(com.example.aspect.MyComment)")public void point(){}@Before("point()")public void methodBefore(){System.out.println("Before");}@AfterReturning("point()")public void methodAfterReturning(){System.out.println("AfterReturning");}@After("point()")public void methodAfter(){System.out.println("After");}
}
@Service
public class UserService {@MyCommentpublic void update(){System.out.println("执行了UserService的update方法");}
}

在这里插入图片描述
注意:@AfterReturning 如果方法中异常不会执行❗

@AfterThrowing恰恰相反,只有出现异常才会执行

在切面类中增加 @AfterThrowing注解的方法

    @AfterThrowing("point()")public void methodAfterThrowing(){System.out.println("AfterThrowing");}

让需要增加的方法报错

@Service
public class UserService {@MyCommentpublic void update(){System.out.println("执行了UserService的update方法");System.out.println(1/0);}
}

执行结果:
在这里插入图片描述

可以看到没有执行@AfterReturning相应的方法,而是执行了@AfterThrowing相应的方法

以上注解都比较简单,只需要知道他们运行的时机即可,重中之重还是@Around

切面类:

@Component
@Aspect
public class MyAspect {@Pointcut("@annotation(com.example.aspect.MyComment)")public void point(){}@Around("point()")public void methodAround(){System.out.println("Around");}
}

切点

@Service
public class UserService {@MyCommentpublic void update(){System.out.println("执行了UserService的update方法");}
}

运行结果:
在这里插入图片描述

虽然执行了@Around相应的方法,但是结果中并没有UserService中的对应的输出语句,这是为什么? 这就是@Around的奇妙之处了

如果想要目标方法执行,需要添加一个ProceedingJoinPoint类型的参数,同时调用里面的proceed()方法:

@Around("point()")
public void methodAround(ProceedingJoinPoint joinPoint){System.out.println("Around");try {joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}
}

此时就可以正常执行目标方法了
在这里插入图片描述
但@Around的用处远不止这些,它可以完成其它4个注解的作用

只需要添加@Around注解的相应方法这么改就可以了.

    @Around("point()")public void methodAround(ProceedingJoinPoint joinPoint){System.out.println("方法执行前");try {joinPoint.proceed();System.out.println("方法执行后");} catch (Throwable e) {System.out.println("方法出现异常");throw new RuntimeException(e);}finally {System.out.println("finally进行增强");}}

8. 总结

Spring的AOP基于代理模式实现,它使用代理对象(Proxy)来包装目标对象(Target),从而实现在目标对象的方法执行前、执行后或抛出异常时插入额外的逻辑。可以通过使用注解或配置文件来定义切面和切点,从而将横切关注点应用到目标对象的方法中。

Spring的AOP提供了一系列通知(Advice)类型,如前置通知(Before)、后置通知(After)、环绕通知(Around)、异常通知(AfterThrowing)和最终通知(AfterReturning),可以根据需要选择合适的通知类型来实现特定的横切关注点功能。

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

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

相关文章

分布式锁~

分布式锁 分布式锁是在分布式系统中用于协调多个节点之间对共享资源的访问的一种机制。个人认为实现分布式锁&#xff0c;需要一个中间件例如数据库&#xff0c;redis等等这样的存储锁即可实现分布式锁。 分布式锁实现方案 基于数据库(唯一索引) 基于内存(redis&#xff0c;…

【QT系列教程】之二创建项目和helloworld案例

文章目录 一、QT创建项目1.1、创建项目1.2、选择创建项目属性1.3、选择路径和项目名称1.4、选择构建项目类型1.5、布局方式1.6、翻译文件&#xff0c;根据自己需求选择1.7、选择套件1.8、项目管理&#xff0c;自行配置1.9、配置完成&#xff0c;系统自动更新配置 二、QT界面介绍…

wpf devexpress 自定义统计

总计统计和分组统计包含预定义总计函数。这些函数允许你计算如下&#xff1a; 数据列的数量&#xff08;Count&#xff09; 最大和最小值(Max和Min) 总计和平均值&#xff08;Sum和Average&#xff09; 处理GridControl.CustomSummary 事件或者使用 GridControl.CustomSumm…

51单片机+DS1302设计一个电子钟(LCD1602显示时间)

一、前言 电子钟是一种能够准确显示时间的设备&#xff0c;广泛应用于家庭、办公场所和公共场所&#xff0c;为人们提供了方便和准确的时间信息。本项目设计一个基于51单片机的电子钟&#xff0c;使用DS1302作为RTC时钟芯片&#xff0c;LCD1602作为显示屏&#xff0c;并通过串…

torch_cluster、torch_scatter、torch_sparse三个包的安装

涉及到下面几个包安装的时候经常会出现问题&#xff0c;这里我使用先下载然后再安装的办法&#xff1a; pip install torch_cluster pip install torch_scatter pip install torch_sparse 1、选择你对应的torch版本&#xff1a;https://data.pyg.org/whl/ 2、点进去然后&…

网络安全-学习手册

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习…

C#检查服务状态,以及进行服务启停

1. linux环境 linux环境通过执行bash命令直接执行&#xff1a; public string RunCmdLinux(string cmd){var proc new Process();System.Console.Write($"Run Linux cmd > [{cmd}] START!");proc.StartInfo.CreateNoWindow true;proc.StartInfo.FileName &…

git clone:SSL: no alternative certificate subject name matches target host name

git clone 时的常见错误&#xff1a; fatal: unable to access ‘https://ip_or_domain/xx/xx.git/’: SSL: no alternative certificate subject name matches target host name ‘ip_or_domain’ 解决办法&#xff1a; disable ssl verify git config --global http.sslVe…

Redis分布式锁(中)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我们在不久前介绍了Spr…

JavaEE初阶(18)(JVM简介:发展史,运行流程、类加载:类加载的基本流程,双亲委派模型、垃圾回收相关:死亡对象的判断算法,垃圾回收算法,垃圾收集器)

接上次博客&#xff1a;初阶JavaEE&#xff08;17&#xff09;Linux 基本使用和 web 程序部署-CSDN博客 目录 JVM 简介 JVM 发展史 JVM 运行流程 JVM的内存区域划分 JVM 执行流程 堆 堆的作用 JVM参数设置 堆的组成 垃圾回收 堆内存管理 类加载 类加载的基本流…

Flink(五)【DataStream 转换算子(上)】

前言 这节注定是一个大的章节&#xff0c;我预估一下得两三天&#xff0c;涉及到的一些东西不懂就重新学&#xff0c;比如 Lambda 表达式&#xff0c;我只知道 Scala 中很方便&#xff0c;但在 Java 中有点发怵了&#xff1b;一个接口能不能 new 来构造对象? 答案是可以的&…

Vue模板语法

模板语法有两大类&#xff1a; 1.插值语法 2.指令语法 让我为大家介绍一下吧&#xff01; 一、插值语法 功能:用于解析标签体内容。 写法: {{xxx}}&#xff0c;xxx是js表达式&#xff0c;且可以直接读取到data中的所有属性。 举个例子&#xff1a; <!DOCTYPE html> &l…

idea maven 构建本地jar包及pom文件

1、设置模块build 本地输出路径 <build><defaultGoal>compile</defaultGoal><resources><resource><directory>${basedir}/src/main/resources</directory><includes><include>**/**</include></includes>…

腾讯云服务器可用区是什么意思?

腾讯云服务器可用区是什么意思&#xff1f;云服务器可用区如何选择&#xff1f;可用区是指在同一个地域内电力和网络相互独立的区域&#xff0c;可用区可以做到故障隔离&#xff0c;所以可用区存在的意义在于构建高可用、高容灾应用&#xff0c;将应用部署在不同可用区内&#…

ChatkBQA:一个基于大语言模型的知识库问题生成-检索框架11.13

ChatkBQA&#xff1a;一个基于大语言模型的知识库问题生成-检索框架 摘要1 引言3 准备工作4 方法4.1 ChatKBQA概述4.2 在LLMS上进行高效微调4.3 用微调LLMS生成逻辑形式4.4 实体和关系的非监督检索4.5 可解释查询执行 摘要 基于知识的问答&#xff08;KBQA&#xff09;旨在从大…

Windows Server 2012 R2系统服务器远程桌面服务多用户登录配置分享

Windows Server 2012系统在没有安装远程多界面的情况下&#xff0c;最多只能同时运行2个远程桌面&#xff0c;如果是有多个技术员、合伙人同时操作或是像游戏开发需要用到多界面&#xff0c;但是没有安装就很不方便&#xff0c;今天飞飞来和你们分享Windows server 2012R2系统远…

C++ opencv基本用法【学习笔记(九)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、vs code 结合Cmake debug1.1 配置tasks.json1.2 配置launch.json 二、图片、视频、摄像头读取显示2.1 读取图片并显示2.2 读取视频文件并显示2.3 读取摄像头并写入文件 三、图片基…

通过注释来埋点

目录 开始 插件编写 功能一 功能二 功能三 合并功能 运行代码 总结 这篇文章主要讲如何根据注释&#xff0c;通过babel插件自动地&#xff0c;给相应函数插入埋点代码&#xff0c;在实现埋点逻辑和业务逻辑分离的基础上&#xff0c;配置更加灵活 这篇文章想要达到的效…

2023最受推荐的五款项目管理工具

1、进度猫 进度猫是国内一款轻量级项目管理工具&#xff0c;适用于实时协作的团队。 以甘特图为向导&#xff0c;基于任务清单todolist&#xff0c;支持多用户协作&#xff1b; 甘特图显示具体任务清单、时间和任务的进度&#xff1b; 对未完成任务、已完成任务进行分类管…

Vue3源码reactive和readonly对象嵌套转换,及实现shallowReadonly

前言 官方文档中对reactive的描述&#xff1a; 响应式转换是“深层”的&#xff1a;它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性&#xff0c;同时保持响应性。 官方文档中对readonly的描述: 只读代理是深层的&#xff1a;对任何嵌套属性的访问都将是…