Spring AOP(2)
目录
Spring AOP详解
@PointCut
切面优先级@Order
切点表达式
execution表达式
切点表达式示例
@annotation
自定义注解@MyAspect
切面类
添加自定义注解
Spring AOP详解
@PointCut
上面代码存在一个问题, 就是对于excution(* com.example.demo.controller.*.*(..))的大量重复使用, Spring提供了@PointCut注解, 把公共的切点表达式提取出来, 需要用到时引入切点表达式即可.
@Slf4j
@Component
@Aspect
public class AspectDemo {//声明一个切点@Pointcut("execution(* com.bite.aop.controller.*.*(..))")public void pt(){}; //切点名称:pt()@Before("pt()")public void doBefore() {//此处省略...}@After("pt()")public void doAfter() {//此处省略...}@Around("pt()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {//此处省略...}@AfterReturning("pt()")public void doAfterReturning() {//此处省略...}
}
当切点定义为private修饰时, 仅能在当前切面类使用, 当其他切面类也要使用当前切点定义时, 就需要把private改为public. 引用方式为: 全限定类名.方法名()
使用示例:
@Slf4j
@Aspect
@Component
public class AspectDemo2 {//前置通知@Before("com.example.demo.aspect.AspectDemo.pt()")public void doBefore() {log.info("卢本伟牛逼");}
}
切面优先级@Order
当我们在一个项目中, 定义了多个切面类时, 并且这些切面类的多个切入点都匹配到了同一个目标方法. 当目标方法运行的时候, 这些切面类中的通知方法都会执行, 那么这些通知方法的执行顺序是怎样的呢?
还是通过程序求证:
定义多个切面类如下:
@Component
public class AspectDemo2 {@Pointcut("execution(* com.example.demo.controller.*.*(..))")private void pt(){}//前置通知@Before("pt()")public void doBefore() {log.info("执⾏ AspectDemo2 -> Before ⽅法");}//后置通知@After("pt()")public void doAfter() {log.info("执⾏ AspectDemo2 -> After ⽅法");}
}@Component
public class AspectDemo3 {@Pointcut("execution(* com.example.demo.controller.*.*(..))")private void pt(){}//前置通知@Before("pt()")public void doBefore() {log.info("执⾏ AspectDemo3 -> Before ⽅法");}//后置通知@After("pt()")public void doAfter() {log.info("执⾏ AspectDemo3 -> After ⽅法");}
}@Component
public class AspectDemo4 {@Pointcut("execution(* com.example.demo.controller.*.*(..))")private void pt(){}//前置通知@Before("pt()")public void doBefore() {log.info("执⾏ AspectDemo4 -> Before ⽅法");}//后置通知@After("pt()")public void doAfter() {log.info("执⾏ AspectDemo4 -> After ⽅法");}
}
运行指定接口,可以得到日志:
通过上述程序的运行结果, 可以看出:
存在多个切面类时, 默认按照切面类的类名字母排序:
@Before通知: 字母排名靠前的先执行;
@After通知: 字母排名靠后的后执行.
但是哥们不想这么搞, 哥们想让它们按照哥们的想法排序, 到这里我们就可以使用@Order来对切面优先级排序.
使用方式如下:
@Aspect
@Component
@Order(2)
public class AspectDemo2 {//代码省略...
}@Aspect
@Component
@Order(1)
public class AspectDemo3 {//代码省略...
}@Aspect
@Component
@Order(3)
public class AspectDemo4 {//代码省略...
}
执行结果如下:
通过上述程序的运行结果, 得出结论:
@Order注解标识的切面类, 执行顺序如下:
@Before通知: 数字越小先执行
@After通知: 数字越大先执行
@Order控制切面的优先级控制切面的优先级, 先执行优先级较高的切面, 在执行优先级较低的切面, 最终执行目标方法.
切点表达式
上面的代码中, 我们一直在使用切点表达式来描述切点, 下面我们来介绍一下切点表达式的语法.
切点表达式常见有两种表达方式
1.execution(......): 根据方法的签名来匹配
2.annotation(......): 根据注解来匹配.
execution表达式
execution()作为常用的表达式, 语法为:
execution(<访问修饰符> <返回类型> <包名.类名.方法(方法参数)> <异常>)
其中: 访问修饰符和异常可以省略.
切点表达式支持通配符表达:
1. * : 匹配任意字符, 只匹配任意一个元素(返回类型, 包, 类名, 方法名, 方法参数)
2. .. :匹配多个连续的任意符号, 可以通配任意层级的包, 或任意类型, 任意个数的参数
切点表达式示例
TestController下的public 修饰, 返回类型为String方法名为t1, 无参方法
execution(public String com.example.demo.controller.TestController.t1())
省略访问修饰符:
execution(String com.example.demo.controller.TestController.t1())
匹配所有类型:
execution(* com.example.demo.controller.TestController.t1())
匹配TestController下的所有无参方法:
execution(* com.example.demo.controller.TestController.*())
匹配TestController下的所有方法
execution(* com.example.demo.controller.TestController.*(..))
匹配controller包下所有类的所有方法:
execution(* com.example.demo.controller.*.*(..))
匹配所有包下的TestController
execution(* com..TestController.*(..))
@annotation
execution表达式更适用于有规则的, 如果我们要匹配出多个无规则的方法呢? 比如: 匹配TestController中的t1(), 和UserController中的u1()这两个方法.
这个时候使用execution就不是很方便了, 因此这里引入@annotation来表示这一类的切点.
实现步骤:
1.编写自定义注解
2.使用@annotation表达式来描述切点
3.在连接点的方法上添加自定义注解.
准备测试代码:
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {@MyAspect@RequestMapping("/t1")public String t1() {log.info("执行t1方法...");return "t1";}@RequestMapping("/t2")public boolean t2() {log.info("执行t2方法");return true;}
}@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@RequestMapping("/u1")public String u1() {log.info("执行u1方法...");return "u1";}@MyAspect@RequestMapping("/u2")public boolean u2() {log.info("执行u2方法");return true;}
}
自定义注解@MyAspect
创建一个注解类:
定义如下代码:
//注解类型
@Target({ElementType.METHOD})
//注解生命周期
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {}
这里只做简单说明, 不必深究:
1.@Target标识了Annotation所修饰对象的范围, 即该注解用于什么地方(上文就是用于方法)
2.@Retention指Annotation被保留的时间长短, 标明注解的生命周期.
切面类
使用@annotation切点表达式定义切点, 只对@MyAspect生效.
切面类代码如下:
@Slf4j
@Component
@Aspect
public class MyAspectDemo {//前置通知@Before("@annotation(com.example.demo.aspect.MyAspect)")public void before() {log.info("MyAspect -> before ...");}//后置通知@After("@annotation(com.example.demo.aspect.MyAspect)")public void after() {log.info("MyAspect -> after ...");}
}
添加自定义注解
在TestController中的t1()和 UserController中的u1()这两个方法上添加自定义注解 @MyAspect.
@MyAspect@RequestMapping("/t1")public String t1() {log.info("执行t1方法...");return "t1";}@MyAspect@RequestMapping("/u2")public boolean u2() {log.info("执行u2方法");return true;}
顺利执行.
Spring AOP实现方式(常见面试题)
1.基于注解@Aspect
2.基于自定义注解
3.基于Spring API(现在很少见)
4.基于代理实现(笨重, 不建议使用).
相关文章:

Spring AOP(2)
目录 Spring AOP详解 PointCut 切面优先级Order 切点表达式 execution表达式 切点表达式示例 annotation 自定义注解MyAspect 切面类 添加自定义注解 Spring AOP详解 PointCut 上面代码存在一个问题, 就是对于excution(* com.example.demo.controller.*.*(..))的大量重…...

Spring-依赖注入的处理过程
前置知识 1 入口 DefaultListableBeanFactory#resolveDependency 2 每个依赖都有对应的DependencyDescriptor 3 自定绑定候选对象处理器AutowireCapableBeanFactory 注入处理 我们可以看到接口AutowireCapableBeanFactory中有两个方法。 第一个是单个注入: Null…...
2.用python爬取的保存在text文件中的格式为MP4的视频url
文章目录 一、url的保存格式二、MP4视频获取 一、url的保存格式 爬取的视频名字和url保存在text文件中,每一个视频都是一个单独的text,其中text的文件名就是视频的名字,text内容是视频的下载url,并且所有的text都保存在同一个文件…...

Java基于B/S医院绩效考核管理平台系统源码java+springboot+MySQL医院智慧绩效管理系统源码
Java基于B/S医院绩效考核管理平台系统源码javaspringbootMySQL医院智慧绩效管理系统源码 医院绩效考核系统是一个关键的管理工具,旨在评估和优化医院内部各部门、科室和员工的绩效。一个有效的绩效考核系统不仅能帮助医院实现其战略目标,还能提升医疗服…...

UE 蓝图堆栈调试
蓝图打断点后如果想查看断点前的执行逻辑,Tools→Debug→BlueprintDebugger 然后打断点运行,执行顺序是从下往上...

UE4_摄像机_使用摄像机的技巧
学习笔记,不喜勿喷!祝愿生活越来越好! 知识点: a.相机跟随。 b.相机抖动。 c.摄像机移动 d.四元数插值(保证正确旋转方向)。 e.相机注视跟踪。 1、新建关卡序列,并给小车添加动画。 2、创…...

ssm115乐购游戏商城系统+vue
毕业生学历证明系统 设计与实现 内容摘要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统毕业生学历信息管理难…...

【可实战】被测需求理解(需求文档是啥样的、从哪些角度进行需求评审、需求分析需要分析出哪些内容、如何提高需求分析能力)
产品人员会产出一个需求文档,然后组织一个需求的宣讲。测试人员的任务就是在需求宣讲当中,分析需求有没有存在一些问题,然后在需求宣讲结束之后通过分析需求文档,分析里面的测试点并预估一个排期。 一、需求文档是什么样的&#x…...
伪类和伪元素的区别是什么?
一、两者的定义 1.伪类(pseudo-class)是一个以冒号作为前缀,被添加到一个选择器末尾的关键字,当你希望样式在特定状态才被呈现到指定的元素时,你可以往元素的选择器后面加上对应的伪类。 2.伪元素用于创建一些不在文档…...

gorm-sharding分表插件升级版
代码地址: GitHub - 137/gorm-sharding: Sharding 是一个高性能的 Gorm 分表中间件。它基于 Conn 层做 SQL 拦截、AST 解析、分表路由、自增主键填充,带来的额外开销极小。对开发者友好、透明,使用上与普通 SQL、Gorm 查询无差别.解决了原生s…...

MoviePy(Python音视频开发)
音视频基础帧率、码率、分辨率视频格式H.264和H.265视频压缩算法 Moviepy常见剪辑类VideoFlieClipImageFlieClipColorClipTextClipCompositeVideoClipAudioFlieClipCompositeAudioClip 常见操作音视频的读入与导出截取音视频 音视频基础 帧率、码率、分辨率 体积(V…...
Spring中的FileCopyUtils:文件复制的利器与详解
1. 概述 在Spring框架中,FileCopyUtils是一个用于文件复制操作的实用工具类。它提供了一系列静态方法,简化了文件从输入流到输出流、从文件到文件等的复制过程。这些方法都基于NIO(New I/O)技术,提供了高效的文件复制…...
【操作系统】读者—写者问题python解析
一个数据问价或记录可以被多个进程共享,我们把只读该文件的进程称为“读者进程”,其他进程为“写者进程”。允许多个进程同时读一个共享对象,但不允许一个写者进程和其他写者进程或读者进程同时访问共享对象。即:保证一个写者进程…...

【driver5】调用堆栈函数,printk,动态打印,ftrace,proc,sysfs
文章目录 1.内核函数调用堆栈:4个函数2.printk:cat /proc/cmdline查看consolettyS03.动态打印:printk是全局的且只能设打印等级,动态打印可控制选择模块的打印,在内核配置打开CONFIG_DYNAMIC_DEBUG4.top&perf&…...

计算机毕业设计springboot基于vue电商抢购限时秒杀系统ch0h8
技术栈 ide工具:IDEA 或者eclipse 编程语言: java 数据库: mysql5.7以上版本 可选框架:ssmspringboot都有的 前端:vue.jsElementUI 详细技术:springbootSSMvueMYSQLMAVEN 数据库工具:Navicat/SQLyog都可以 开发工具 Ec…...

顺序表的实现(迈入数据结构的大门)(2)
目录 顺序表的头插(SLPushFront) 此时:我们有两个思路(数组移位) 顺序表的头删(学会思维的变换)(SLPopFront) 顺序表的尾插(SLPushBack) 有尾插就有尾删 既然头与尾部的插入与删除都有,那必然少不了指定位置的插入删除 查找…...
学习笔记:IEEE 1003.13-2003【POSIX PSE51接口列表】
一、POSIX PSE51接口列表 根据IEEE 1003.13-2003,整理了POSIX PSE51接口API(一共286个),每个API支持链接查看。详细内容参考下面表格: SN Module/_POSIX_宏 Function File 1 POSIX_C_LANG_JUMP(2) longjmp() &…...

《QT实用小工具·五十》动态增删数据与平滑缩放移动的折线图
1、概述 源码放在文章末尾 该项目实现了带动画、带交互的折线图,包含如下特点: 动态增删数值 自适应显示坐标轴数值 鼠标悬浮显示十字对准线 鼠标靠近点自动贴附 支持直线与平滑曲线效果 自定义点的显示类型与大小 自适应点的数值显示位置 根据指定锚点…...

【qt】核心机制信号槽(下)
这里写目录标题 自定义的信号自定义的槽自定义的信号和槽的结合使用信号和槽的断开总结: 自定义的信号 信号就是一个函数声明 前面咱们都用的qt组件自带的信号,接下来我们自己写一个信号。 信号只需要在前面加一个signals即可 这个函数不需要实现 参数传…...

C++ 基础 输入输出
一 C 的基本IO 系统中的预定义流对象cin和cout: 输入流:cin处理标准输入,即键盘输入; 输出流:cout处理标准输出,即屏幕输出; 流:从某种IO设备上读入或写出的字符系列 使用cin、cout这两个流对…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...