Spring Boot Aop初接触
AOP(面向切面编程),或多或少都听过一点。名字比较怪,切面,不容易理解,但其中真正含义,无非就是旁路控制,非侵入式编码之类。比如我想加个操作日志功能,利用AOP,无须每个操作都加一个记录功能,只需写一个,就惠泽全部。
这个是怎么做到的呢?也没有太玄妙的东西,原理类似于过滤器、拦截器,在底层和全局性的地方做了处理,各个业务功能都流经这些关卡。
一、过滤器、拦截器与AOP
据说,过滤器、拦截器、AOP三者功能类似,但各有优势,从过滤器 》拦截器 》切面,拦截规则越来越细致,执行顺序依次是过滤器、拦截器、切面。一般情况下数据被过滤的时机越早对服务的性能影响越小,因此我们在编写相对比较公用的代码时,优先考虑过滤器,然后是拦截器,最后是AOP。
AOP使用的主要是动态代理 , 过滤器使用的主要是函数回调;拦截器使用是反射机制 。一个请求过来,先进行过滤器处理,看程序是否受理该请求 。 过滤器放过后 , 程序中的拦截器进行处理 ,处理完后进入 被 AOP动态代理重新编译过的主要业务类进行处理 。
Filter:和框架无关,过滤器拦截的是URL,可以控制最初的http请求,但是更细一点的类和方法控制不了。
Interceptor:拦截器拦截的也是URL,拦截器有三个方法,相对于过滤器更加细致,有被拦截逻辑执行前、后等。
AOP:面向切面拦截的是类的元数据(包、类、方法名、参数等) 相对于拦截器更加细致,而且非常灵活,拦截器只能针对URL做拦截,而AOP针对具体的代码,能够实现更加复杂的业务逻辑。
二、Spring Boot中应用AOP
1、pom.xml
引入依赖包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、面向切面类
1)写一个方法用于测试
为方便测试,写一个控制器。再简单不过的控制器。
TestController.java
package com.chenqu.bullshit.modules.work.controller;@RestController
@RequestMapping("test1")
public class TestController {@ResponseBody@RequestMapping("/hello")public String sayHello(){System.out.println("hello");return "hello";}
}
2)面向切面的类
然后写一个面向切面的类。就像配置、过滤器、拦截器一样,写出来之后,系统(准确来说,应该是容器?)会自动解释它,于是面向切面开始生效。
TestAdvice.java
@Aspect
@Component
public class TestAdvice {//指示哪些方法将会受到影响。Pointcut,切入点@Pointcut("execution (* com.chenqu.bullshit.modules.work.controller.TestController.*(..))")public void test1() {}@Before("test1()")public void beforeAdvice() {System.out.println("beforeAdvice...");}@After("test1()")public void afterAdvice() {System.out.println("afterAdvice...");}@Around("test1()")public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {System.out.println("before");try {proceedingJoinPoint.proceed();} catch (Throwable t) {t.printStackTrace();}System.out.println("after");}
}
上述代码中,首先类使用了标注“@Aspect”,表明这是一个面向切面的类。
类中void test1()使用了标注“@Pointcut”。Pointcut者,切入点也。它里面的内容,指示了哪些方法将会受到影响。在这里,指向了我们用于测试的控制器。如果是想指向所有的控制器,可以这样写:
@Pointcut("execution (* com.chenqu.bullshit.modules.work.controller.*.*(..))")
至于其他的什么@Before、@After、@Arround,无非就是切入前执行、切入后执行、切入时执行,顾名思义。
运行代码,用浏览器访问
http://localhost:8090/test1/hello
控制台输出如下:
3、execution 与 annotation
execution与annotation都是Pointcut的2种常用执行方式,除此而外,还有什么within、this、target之类乱七八糟的,一大群,让人头大。常用的就是execution与annotation。execution如上例,就是指明会影响哪些方法;而annotation是注解的意思,指明会影响带哪些注解的方法,或者说,如果方法带上指定的注解,就会受到影响。
1)添加一个名为NeedTest的注解
NeedTest.java
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NeedTest {String value() default "";
}
2)然后将上面例子中TestAdvice.java,Pointcut的执行方式由execution 改为 annotation,其余保持不变。
@Aspect
@Component
public class TestAdvice {@Pointcut("@annotation(com.chenqu.bullshit.modules.annotation.NeedTest)")public void test1() {}@Before("test1()")public void beforeAdvice() {System.out.println("beforeAdvice...");}@After("test1()")public void afterAdvice() {System.out.println("afterAdvice...");}@Around("test1()")public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {System.out.println("before");try {proceedingJoinPoint.proceed();} catch (Throwable t) {t.printStackTrace();}System.out.println("after");}}
3)修改用于测试的控制器TestController.java,方法带上@NeedTest注解
package com.chenqu.bullshit.modules.work.controller;@RestController
@RequestMapping("test1")
public class TestController {@NeedTest@ResponseBody@RequestMapping("/hello")public String sayHello(){System.out.println("hello");return "hello";}
}
运行结果跟上面一样,效果一致。
三、小结
从网上搜索出来的,有关spring boot aop的使用资料,绝大部分都很难懂。说了一大堆,根本不知道在说什么,也许作为手册供查阅是极好的。本文从我个人学习的角度出发,记录一下心得。
参考文章:
Spring Boot使用AOP的正确姿势
相关文章:

Spring Boot Aop初接触
AOP(面向切面编程),或多或少都听过一点。名字比较怪,切面,不容易理解,但其中真正含义,无非就是旁路控制,非侵入式编码之类。比如我想加个操作日志功能,利用AOP࿰…...

【创作赢红包】LeetCode:232. 用栈实现队列
🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀算法专栏: 👉🏻123 一、🌱232. 用栈实现队列 题目描述:请你仅使用两个栈实现先入先出队…...
Mybatis+Mysql 实现向下递归查询
介绍 说到递归查询,大家可以想到的技术实现方式主要如下几种: 1、各种主流应用开发语言本身通过算法实现 2、各种数据库引擎自身提供的算法实现 本文提到主要是针对第二种和第一种的结合 主要技术栈 1、ORM:Mybatis 2、DB:MyS…...
python@调用系统命令行@os.system@subprocess@标准输入输出@sys.stdin@sys.stdout@input@print
文章目录python调用系统命令行os.system标准输入输出sys.stdinsys.stdoutinputprint概要os.systemdemoswindows命令解释器ComSpecsubprocessrecommended🎈基本用法demos标准输入输出sys.stdininput()sys.stdin.inputinput()交互模式小结sys.stdoutsys.stdout.wirte(…...

手握数据智能密钥,诸葛智能打开数字化经营“三重门”
科技云报道原创。 如果说上世纪传统麦迪逊大街上的“广告狂人”吸金立足之本,还主要是基于“Big Idea”的话,那么在当下,数据正在成为企业营销和运营的金矿。 这是一个“人与机器共同进化”的时代,技术作为延伸人类感觉的媒介之…...
C语言可以实现各种滤波算法
C语言可以实现各种滤波算法,以下是一些常见的滤波算法: 均值滤波(Mean Filter):将图像中每一个像素周围一定区域内的灰度值取平均值作为该像素的新灰度值,用于去除高斯噪声等随机噪声。 下面是一个简单的 C…...
使用Netty,当然也要了解它的连接闲置处理
连接闲置网络连接的闲置指的是当前网络连接处于空闲状态,即没有正在进行的数据传输或通信活动。当我们的某个连接不再发送请求或者接收响应的时候,这个连接就开始处于闲置状态。网络连接的闲置时间越长,说明该连接越不活跃。此时,…...

2、K-Planes
运行配置 主页:https://sarafridov.github.io/K-Planes/ 代码:https://github.com/sarafridov/K-Planes 预训练权重:https://drive.google.com/drive/folders/1zs_folzaCdv88y065wc6365uSRfsqITH Neural_3D_Video_Dataset:htt…...

张文海教授课题组在国际高水平期刊《Cerebral Cortex》发表研究成果
调节悲伤情绪对于维持伴侣间的浪漫关系至关重要。人际情绪调节策略包括情感参与(AE)和认知参与(CE),这两种策略在浪漫关系中效用如何?它们是如何通过情感纽带调节伴侣情绪的?其背后的脑际神经互…...
ffmpeg4.1 源码学习之-转封装
前言 ffmpeg 的源码量非常的多,而且非常繁杂,非常多的函数,如果一个函数一个函数看的话要花费比较多的时间。所以本文通过跟踪ffmpeg转封装的过程来学习ffmpeg的源码具体转封装的命令:ffmpeg -i 1_cut.flv -c copy -f mp4 1.mp4在…...

ChatGPT写作文章-快速使用ChatGPT不用注册方式
如何更好地使用ChatGPT批量生成文章:详细教程 作为一款强大的文本生成器,ChatGPT可以帮助您快速、高效地批量生成文章。但如果您还不知道如何更好地使用ChatGPT,那么这篇详细的列表教程将会指导您如何使用它来生成高质量的文章,提…...
Nginx配置ip白名单(服务权限控制)
Nginx服务器权限控制:Nginx 是一款高性能的 HTTP 和反向代理服务器。它可以通过配置文件实现权限控制,从而限制或允许特定的 IP 地址、网络或用户访问指定的资源。这里是一些基本的 Nginx 权限控制方法: 1. 基于 IP 地址的访问控制 在 Ngin…...

Vue 核心(二)
文章目录Vue 核心(二)八、 绑定样式1、 class2、 style九、 条件渲染1、 渲染指令2、 使用示例十、 列表渲染1、 基本语法2、 key原理3、 列表过滤4、 列表排序5、 数组更新检测6、 大总结十一、 收集表单数据十二、 内置指令1、 v-text2、 v-html3、 v-…...

犯罪现场还原虚拟vr训练平台突破各种教学限制
在当今社会矛盾日益凸显、各式犯罪层出不穷的背景下,创新改革公安院校实战化教学方式,强化对基层公安队伍实战化应用型人才的供给能力具有重要性、紧迫性。 案件现场勘查是门技术活,如何让民警快速有效提升技能、服务实战? 常规刑侦专业现场…...

LeetCode 617. 合并二叉树 | C++语言版
LeetCode 617. 合并二叉树 | C语言版LeetCode 617. 合并二叉树题目描述解题思路思路一:使用递归代码实现运行结果参考文章:思路二:减少遍历节点数代码实现运行结果参考文章:LeetCode 617. 合并二叉树 题目描述 题目地址…...

Python量化交易08——利用Tushare获取日K数据
总有同学问我要数据...很多第三方接口都能直接获取数据的,本次介绍怎么用Tushare库获取A股日k线行情的数据。 Tushare有两个版本,老版现在快弃用了。 新版的官网链接在这:Tushare数据 需要注册一个账号,然后改一下资料࿰…...

30张精美可视化大屏,无需代码直接套用,解决你95%的大屏需求!
通常制作可视化大屏,一般有两种方式 代码开发:写代码调用数据和图表库,比如写JSEcharts ; 可视化工具:用现成的数据可视化工具 前者简单直接,直接写代码就完事。但对于大部分人来说门槛较高,维…...

TCP网络事件模型的封装1.0
TCP网络模型的封装 最近学习了TCP网络模型的封装,其中运用的封装技术个人感觉有点绕 在反复读代码、做思维导图下初步理解了这套封装模型,不禁感叹原来代码还能这样写?神奇! 为此将源码分享出来并将流程图画出,方便…...

NC271.二叉搜索树的后序遍历序列
文章目录一、题目描述二、示例三、主要思路一、题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回 true ,否则返回 false 。假设输入的数组的任意两个数字都互不相同。 提示: 1.二叉搜索树是指父亲节点大于左子树中…...

研究fastdds v2.8.0 1之 基础模块
阅读 dds 协议 1.4 版本 , 结合fastdds 2.8 的代码理解dds。 Entity 理解 DCPS基础设施模块由以下类组成: Entity DomainEntity QosPolicy Listener Status WaitSet Condition GuardCondition StatusCondition1、Entity 是所有DCPS 对象的基础类 virt…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...