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

【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),可以根据需要选择合适的通知类型来实现特定的横切关注点功能。

相关文章:

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

文章目录 1. 前言2. 什么是AOP3. AOP快速入门4. AOP的核心概念5. 切点表达式6. 切点函数7. 通知8. 总结 1. 前言 本文围绕AOP进行讲解,AOP可以做什么,涉及到了哪些注解,以及各个注解运行的时机,以及Around相较于其它注解有什么不同,并且如果要执行目标方法需要怎么做 2. 什么…...

界面组件DevExpress Reporting v23.1亮点 - 全新升级报表查看器

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已经发布一段…...

电容容量换算电池容量,以及RTC持续时间计算

依据 公式1&#xff1a;QI*t 公式2&#xff1a;QC*U 其中&#xff1a; Q&#xff1a; 电荷量 &#xff08;库仑&#xff09; I&#xff1a; 电流 &#xff08;安培&#xff09; t&#xff1a; 时间 &#xff08;秒&#xff09; C&#xff1a; 电容量 &#xff08;法拉&#xf…...

【BIM入门实战】高程点无法放置的解决方法

文章目录 一、问题提出二、解决办法1. 检查模型图形样式2. 高程点可以放置的图元一、问题提出 在平面图中添加高程点时有时会遇到无法在楼板等平面构件上放置高程点,应如何设置才能使高程点正常放置? 如下图所示,楼板上无法放置高程点: 二、解决办法 1. 检查模型图形样式…...

CRM系统对科技企业有哪些帮助

随着国家政策的倾斜和5G等相关基础技术的发展&#xff0c;中国人工智能产业在各方的共同推动下进入爆发式增长阶段&#xff0c;市场发展潜力巨大。CRM客户管理系统作为当下最热门的企业应用&#xff0c;同样市场前景广阔。那么&#xff0c;CRM系统对科技企业有哪些帮助&#xf…...

用excel计算一个矩阵的转置矩阵

假设我们的原矩阵是一个3*3的矩阵&#xff1a; 125346789 现在求它的转置矩阵&#xff1a; 鼠标点到一个空白的地方&#xff0c;用来存放结果&#xff1a; 插入-》函数&#xff1a; 选择TRANSPOSE&#xff0c;这个就是求转置矩阵的函数&#xff1a; 点击“继续”&#xff1a…...

WPF 中的 ControlTemplate 和 DataTemplate 有什么区别

在WPF中&#xff0c;ControlTemplate和DataTemplate都是模板&#xff0c;它们都可以用来定义一段可重复使用的XAML标记。然而&#xff0c;它们的用途和应用场景有很大的不同。 ControlTemplate&#xff1a; ControlTemplate是用来定义控件的外观和视觉行为的。每个WPF控件都有…...

3D重建相关

目录 <font colorblue>整个3D重建的过程是怎样的<font colorblue>体素、网格、点云之间的关系是什么<font colorblue>点云中的颜色怎么处理成最终3D模型上的颜色<font colorblue>点云还原的3D模型的颜色怎么处理&#xff0c;点云有颜色数据&#xff1f…...

字符串数组排序(Java/JavaScript代码版)

Java public static void main(String[] args) throws Exception {String[] arr new String[] {"abc","xyz","efg"};// 默认按自然升序排Arrays.sort(arr);System.out.println(Arrays.toString(arr)); }降序排 降序排&#xff0c;可传入第二个…...

调用电商集成平台 聚水潭 api接口示例

先上工具类 package com.zuodou.utlis;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import javax.xml.crypto.Data; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import j…...

深入Rust:探索所有权和借用机制

大家好&#xff01;我是lincyang。 今天&#xff0c;我们将一起深入探索Rust语言中的一个核心概念&#xff1a;所有权和借用机制。 这些特性是Rust区别于其他语言的重要特点&#xff0c;它们在内存管理和并发编程中扮演着关键角色。 一、Rust所有权机制 1. 什么是所有权&#x…...

Python之冒泡排序(AI自动写文章项目测试)

全自动AI生成文章测试&#xff0c;如有不合理地方&#xff0c;请见谅。 一、冒泡排序简介 1.1 冒泡排序概述 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;通过不断交换相邻元素的位置&#xff0c;将最大&#xff08;或最小&#xff09;的元…...

spring cloud微服务中多线程下,子线程通过feign调用其它服务,请求头token等丢失

在线程池中&#xff0c;子线程调用其他服务&#xff0c;请求头丢失&#xff0c;token为空的情况 看了很多篇文章的处理方法和在自己亲测的情况下做出说明&#xff1a; 第一种&#xff1a; 这种方式只支持在主线程情况下&#xff0c;能够处理&#xff0c;在多线程情况下&#…...

Nacos 高级玩法:深入探讨分布式配置和服务发现

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 Nacos 高级玩法&#xff1a;深入探讨分布式配置和服务发现 前言第一&#xff1a;nacos高级配置管理1. 动态配置的基本使用&#xff1a;2. 监听策略的原理和实现&#xff1a;3…...

CCF CSP认证历年题目自练Day45

这几天搞泰迪杯数据分析技能赛去了。等拿国奖了就出一期关于泰迪杯的。 题目 试题编号&#xff1a; 201703-3 试题名称&#xff1a; Markdown 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   Markdown 是一种很流行的轻量级标记…...

outlook群发邮件

一米群发软件使用Outlook进行群发邮件的步骤如下&#xff1a; 打开Outlook软件&#xff0c;点击页面上方的“新建电子邮件”选项。在弹出的新邮件中&#xff0c;输入收件人和邮件主题&#xff0c;在收件人输入框中输入多个需要接收邮件的邮箱地址&#xff0c;用分号&#xff0…...

【Attack】针对GNN-based假新闻检测器

Attacking Fake News Detectors via Manipulating News Social Engagement AbstractMotivationContributions FormulationMethodologyAttacker Capability&#xff08;针对挑战1&#xff09;Agent Configuration&#xff08;针对挑战3&#xff09; WWW’23, April 30-May 4, 20…...

APIcloud 【现已更名 用友开发中心】 iOS发版 应用程序请求用户同意访问相机和照片,但没有在目的字符串中充分说明相机和照片的使用。

iOS 审核时 提示 首次安装软件 获取相机 相册 提示信息 怎么修改 我们注意到你的应用程序请求用户同意访问相机和照片&#xff0c;但没有在目的字符串中充分说明相机和照片的使用。 为了解决这个问题&#xff0c;修改应用信息中的目的字符串是合适的。相机和照片的Plist文件&a…...

记一次弱口令之后引发的获取服务器权限

文章目录 一、漏洞原因二、漏洞成果三、漏洞利用1、管理员权限2、信息泄露3、服务器权限4、数据库权限5、 PHPMyadmin后台管理系统四、总结五、免责声明一、漏洞原因 由于网站登录口未做双因子校验,导致可以通过暴力破解获取管理员账号,成功进入系统;由于未对个人信息进行脱…...

AJAX入门Day01笔记

Day01_Ajax入门 知识点自测 如下对象取值的方式哪个正确? let obj {name: 黑马 }A: obj.a B: obj()a 答案 A选项正确 哪个赋值会让浏览器解析成标签显示? let ul document.querySelector(#ul) let str <span>我是span标签</span>A: ul.innerText str B: ul…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...