SpringBoot使用AOP详解
目录
- 1 AOP是什么
- 2 AOP概念
- 3 Springboot中使用AOP
- 4 AOP原理
- 5 应用场景
1 AOP是什么
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可对业务逻辑进行增强,在不改变原有逻辑的基础上,在其前后进行处理。降低了耦合性,减少了大量冗余的操作。特别适合用于大量方法都需要进行相同处理的操作。
2 AOP概念
AOP是做了个切面,在不破坏原有方法的基础上,将切面切进去,在其前后进行处理,整体逻辑关系图如下:

- 切面(Aspect):一般是指被
@Aspect修饰的类,代表着某一具体功能的AOP逻辑。 - 切入点(Pointcut):选择对哪些方法进行增强。
- 通知(Advice):对目标方法的增强,有一下五种增强的类型。
- 环绕通知(@Around):内部执行方法,可自定义在方法执行的前后操作。
- 前置通知(@Before):在方法执行前执行。
- 后置通知(@After):在方法执行后执行。
- 返回通知(@AfterReturning):在方法返回后执行。
- 异常通知(@AfterThrowing):在方法抛出异常后执行。
- 连接点(JoinPoint):就是那些被切入点选中的方法。这些方法会被增强处理。
对于各种通知的方法、注解等没有什么特别的操作,具体使用会在后面举例。而切入点是选择对哪些方法生效的定义,那怎么知道它选择的是哪些方法呢?因为有多种匹配方式。
| 表达式类型 | 功能 |
|---|---|
| execution() | 匹配方法,最全的一个 |
| args() | 匹配入参类型 |
| @args() | 匹配入参类型上的注解 |
| @annotation() | 匹配方法上的注解 |
| within() | 匹配类路径 |
| @within() | 匹配类上的注解 |
| this() | 匹配类路径,实际上AOP代理的类 |
| target() | 匹配类路径,目标类 |
| @target() | 匹配类上的注解 |
用的比较多的是execution()和@annotation
-
execution(修饰符 返回值类型 方法名(参数)异常)

语法参数 描述 修饰符 可选,如public,protected,写在返回值前,任意修饰符填 *号就可以返回值类型 必选,可以使用*来代表任意返回值方法名 必选,可以用*来代表任意方法参数 () 代表是没有参数,(…)代表是匹配任意数量,任意类型的参数,当然也可以指定类型的参数进行匹配,如要接受一个String类型的参数,则(java.lang.String), 任意数量的String类型参数:(java.lang.String…)异常 可选,语法: throws 异常,异常是完整带包名,可以是多个,用逗号分隔看几个常用的写法
// 所有方法 execution(* *..*(..)) // 指定参数,即入参本身的类型,不能放其接口、父类 execution(* *..*(java.lang.String, java.lang.String) // 指定方法前缀 execution(* *..*.prefix*(..)) // 指定方法后缀 execution(* *..*.*suffix(..)) // 组合,增强所有方法,但是去掉指定前缀和指定后缀的方法 execution(* *..*(..)) && (!execution(* *..prefix*(..)) || !execution(* *..*suffix(..))) -
@annotation()
匹配方法上的注解,括号内写注解定义的全路径,所有加了此注解的方法都会被增强。
// 增强被指定注解修饰的方法(所有加了@TestAspect注解的都会被) @annotation(com.banmoon.test.annotation.TestAspect) // 指定前缀的注解修饰的方法 @annotation(com.banmoon.test.annotation.Prefix*) // 指定后缀的注解修饰的方法 @annotation(com.banmoon.test.annotation.*Suffix)
3 Springboot中使用AOP
-
引入依赖
其实主要起作用的依赖是第二个,但现在
spring-boot-starter-web启动依赖中已经包含AOP依赖,所以只引入第一个也可。<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency> -
定义一个注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Auth {} -
创建一个切面类
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method;@Aspect @Component public class AuthAspect {/*** 定义了一个切点* 这里的路径填自定义注解的全路径*/@Pointcut("@annotation(com.zz.business.annotations.Auth)")public void authCut() {}@Before("authCut()")public void cutProcess(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();System.out.println("注解方式AOP开始拦截, 当前拦截的方法名: " + method.getName());}@After("authCut()")public void after(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();System.out.println("注解方式AOP执行的方法 :" + method.getName() + " 执行完了");}@Around("authCut()")public Object testCutAround(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("注解方式AOP拦截开始进入环绕通知.......");Object proceed = joinPoint.proceed();System.out.println("准备退出环绕......");return proceed;}/*** returning属性指定连接点方法返回的结果放置在result变量中** @param joinPoint 连接点* @param result 返回结果*/@AfterReturning(value = "authCut()", returning = "result")public void afterReturn(JoinPoint joinPoint, Object result) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();System.out.println("注解方式AOP拦截的方法执行成功, 进入返回通知拦截, 方法名为: " + method.getName() + ", 返回结果为: " + result.toString());}@AfterThrowing(value = "authCut()", throwing = "e")public void afterThrow(JoinPoint joinPoint, Exception e) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();System.out.println("注解方式AOP进入方法异常拦截, 方法名为: " + method.getName() + ", 异常信息为: " + e.getMessage());} }可以看到先是定义了一个切点
authCut,之后前置通知、后置通知、环绕通知等都是绑在这个切点上,在通过切点和指定方法连接起来。 -
连接点方法
该方法加了上面自定义的注解
@Auth@RestController @RequestMapping("/company") @RefreshScope public class CompanyController { @GetMapping("/aopTest")@Authpublic AjaxResult aopTest(@RequestParam String name){//远程调用System.out.println("正在执行接口name" + name);return AjaxResult.success("执行成功" + name);} }
执行后的流程如下图

可以看到环绕通知是包在最外侧的。
4 AOP原理
AOP的代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类。
动态代理:程序执行过程中,使用JDK的反射机制,创建代理类对象,并动态的指定要代理目标类。动态代理涉及到的三个类:
-
InvocationHandler接口:处理器,负责完调用目标方法(就是被代理类中的方法),并增强功能;通过代理类对象执行目标接口中的方法,会把方法的调用分派给调用处理器(InvocationHandler)的实现类,执行实现类中的invoke()方法,我们需要把在该invoke()方法中实现调用目标类的目标方法;
-
Proxy 类:通过 JDK 的 java.lang.reflect.Proxy 类实现动态代理 ,使用其静态方法 newProxyInstance(),依据目标对象(被代理类的对象)、业务接口及调用处理器三者,自动生成一个动态代理对象。
-
Method 类:Method 是实例化的对象,有一个方法叫
invoke(),该方法在反射中就是用来执行反射对象的方法的。
在上述代码中也可以看到,就是拿到了Method类型的对象,可以调用invoke()方法执行,除此之外还可以获取方法的各种属性:getAnnotation-获取注解、getName()-方法名字等等。

5 应用场景
AOP在项目中通常用作一些共通的工作
- 接口方法日志的收集
- 接口方法的权限校验
- 前后对出入参的修改,先查缓存这种需求
相关文章:
SpringBoot使用AOP详解
目录 1 AOP是什么2 AOP概念3 Springboot中使用AOP4 AOP原理5 应用场景 1 AOP是什么 AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续&…...
【Qt】QGroundControl入门1:介绍
1、简介 1.1 QGroundControl QGroundControl是一款开源的无人机地面控制站软件,依赖Qt库,简称QGC。 QGroundControl为任何支持 MAVLink协议 的无人机提供完整的飞行控制和任务规划。QGroundControl为 PX4 和 ArduPilot 驱动的无人机提供驱动配置。 源码:https://github.co…...
第36章_瑞萨MCU零基础入门系列教程之步进电机控制实验
本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...
198.打家劫舍,213.打家劫舍II,337.打家劫舍III
代码随想录训练营第48天|198.打家劫舍,213.打家劫舍II,337.打家劫舍III 198.打家劫舍文章思路代码 213.打家劫舍III文章思路代码 337.打家劫舍III文章思路代码 总结 198.打家劫舍 文章 代码随想录|0198.打家劫舍 思路 d p [ i ] M a x ( d p [ i − …...
msvcp140.dll是什么东西,如何解决msvcp140.dll丢失的问题的方法分享
在现代生活中,电脑已经成为我们工作、学习和娱乐的重要工具。然而,电脑问题的出现往往会给我们的生活带来不便。其中,"msvcp140.dll丢失"是一个常见的电脑问题。本文将详细介绍这个问题的原因和解决方法,帮助大家更好地…...
音视频 SDL vs2017配置
一、首先我把SDL放在了C盘根目录下 二、新建空项目 三、添加main.cpp //main.cpp #include<iostream> #include <SDL.h>int main(int argc, char* argv[]) // main函数头必须这样写,因为SDL把main定义成了宏 {SDL_Delay(3000); // 让窗口在屏幕上保持…...
前端面试要点
0914 JScript深拷贝和浅拷贝(js解构赋值算哪个?) 深拷贝和浅拷贝 回流和重绘 回流和重绘 webpack打包流程 Webpack打包 虚拟DOM 虚拟DOM git合并分支 git合并分支 CSS盒子模型 CSS盒子模型 0911 WebPack分包 webpack分包 ts泛型 ts泛型 优化…...
shell字符串处理之字符串比较
引言 我们在使用shell编写脚本时,经常需要对字符串进行处理,如字符串大小比较、模式匹配、替换、截断等。本文将梳理字符串比较中常见的用法。 字符串比较 1. 直接比较字符串 a$1 b$2 c"" # 等于 if [ $a "abc" ];thenecho $a …...
怎么获取别人店铺的商品呢?
jd.item_search_shop(获得店铺的所有商品) 为了进行电商平台 的API开发,首先我们需要做下面几件事情。 1)开发者注册一个账号 2)然后为每个JD应用注册一个应用程序键(App Key) 。 3)下载JDAPI的SDK并掌握基本的API…...
【数据结构】二叉树的链式结构
【数据结构】二叉树的链式存储结构 二叉树的存储结构 typedef int BTDataType; // 二叉树的结构 typedef struct BinaryTreeNode {BTDataType data; // 树的值struct BinaryTreeNode *left; // 左孩子struct BinaryTreeNode *right;// 右孩子 } BinaryTreeNode;二…...
模拟实现C语言--strlen函数
模拟实现C语言–strlen函数 模拟实现C语言--strlen函数一、strlen函数是什么?二、strlen函数的模拟实现2.1 计数器方式实现strlen函数2.2 不创建临时变量计数器方式实现strlen函数2.3 指针-指针方式实现strlen函数 三、strlen函数的返回类型 一、strlen函数是什么&a…...
Spring Boot + Vue的网上商城之物流系统实现
Spring Boot Vue的网上商城之物流系统实现 思路 当构建一个物流系统时,我们可以按照以下步骤进行: 设计数据模型:首先确定系统中需要存储的数据,例如物流公司信息、物流订单信息等。根据需求设计相应的数据模型,包括…...
释放数据价值这道难题,Smartbi V11有解
《未来简史》预言:数据将成为人们未来的信仰。 未来已来,将至已至。如今,数据所扮演的角色与作用超乎想象。从政府将数据要素列入生产要素之中,到数据驱动型业务场景涌现,企业与组织对于数据及其价值的认可度明显提升…...
Day_14 > 指针进阶(3)> bubble函数
目录 1.回顾回调函数 2.写一个bubble_sort函数 2.1认识一下qsort函数 编辑2.2写bubble_sort函数 今天我们继续深入学习指针 1.回顾回调函数 我们回顾一下之前学过的回调函数 回调函数就是一个通过函数指针调用的函数 如果你把函数的指针(地址)…...
sql中怎么查books表下面的内容
要查询 books 表中的所有内容,你可以使用以下 SQL 语句: USE bookmanagement; -- 选择数据库 SELECT * FROM books; -- 查询books表中的所有内容如果你使用的是命令行界面 (mysql 客户端) 来操作数据库,可以直接在命令提示符中输入上述命令…...
Vulnhub系列靶机---HarryPotter-Aragog-1.0.2哈利波特系列靶机-1
文章目录 方式一信息收集主机发现端口扫描目录扫描wpscan工具 漏洞利用msf工具数据库权限用户权限root提权 方式二信息收集gobuster扫描wpscan扫描 漏洞利用POC 靶机文档:HarryPotter: Aragog (1.0.2) 下载地址:Download (Mirror) 方式一 信息收集 主机…...
.NET 8发布首个RC,比.NET 7的超级快更快
.NET 8 发布了首个 RC。据称 RC 阶段会发布两个版本,正式版将于 2023 年 11 月 14 日至 16 日在 .NET Conf 2023 上推出。.NET 8 是长期支持 (LTS) 版本,将会获得 3 年技术支持。 公告写道,此版本为 Android 和 WASM 引入了全新的 AOT 模式、…...
在 Substance Painter中自定义Shader
为什么要学习在Substance Painter中自定义Shader? 答:需要实现引擎与Substance Painter中的渲染效果一致,材质的配置也一致,所见即所得。 基础概述 首先在着色器设置这里,我们可以查看当前渲染使用的着色器 如果没有…...
【自学开发之旅】Flask-restful-Jinjia页面编写template-回顾(五)
restful是web编程里重要的概念 – 一种接口规范也是一种接口设计风格 设计接口: 要考虑:数据返回、接收数据的方式、url、方法 统一风格 rest–表现层状态转移 web–每一类数据–资源 资源通过http的动作来实现状态转移 GET、PUT、POST、DELETE path…...
input 的 placeholder 样式
::placeholder 伪元素 这个伪元素可以改变 input、textarea 占位文本的样式。 input::placeholder {color: green; }完整的兼容性写法: input {&::-webkit-input-placeholder, /* WebKit browsers*/ &:-moz-input-placeholder, /* Mozilla Firefox 4 to …...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
