AOP切面编程,以及自定义注解实现切面
AOP切面编程
- 通知类型
- 表达式
- 重用表达式
- 切面优先级
- 使用注解开发,加上注解实现某些功能
简介
- 动态代理分为JDK动态代理和cglib动态代理
- 当目标类有接口的情况使用JDK动态代理和cglib动态代理,没有接口时只能使用cglib动态代理
- JDK动态代理动态生成的代理类会在com.sun.proxy包下,类名为$proxy1,和目标类实现相同的接口
- cglib动态代理动态生成的代理类会和目标在在相同的包下,会继承目标类
- 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。
- cglib:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口。
- AspectJ:是AOP思想的一种实现。本质上是静态代理,将代理逻辑“织入”被代理的目标类编译得到的字节码文件,所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
依赖
<!--spring context依赖-->
<!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.2</version>
</dependency><!--spring aop依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.2</version>
</dependency>
<!--spring aspects依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version>
</dependency>
注解说明
@Aspect表示这个类是一个切面类@Component注解保证这个切面类能够放入IOC容器
简单使用
几种通知类型
- 前置通知
@Before() - 环绕通知
@Around() - 返回通知
@AfterReturning() - 异常通知
@AfterThrowing() - 后置通知
@After()
表达式介绍

切入点表达式
在方法中可以传入参数public void afterMethod(JoinPoint joinPoint),类型为JoinPoint
-
获取连接点的签名信息
-
String methodName = joinPoint.getSignature().getName()
-
-
获取目标方法的返回值
-
其中表达式中
returning后面参数result要与public void afterReturningMethod(JoinPoint joinPoint, Object result)传入参数名称一样,类型可以不一样但是名称要一样。 -
@AfterReturning(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result") public void afterReturningMethod(JoinPoint joinPoint, Object result){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:"+methodName+",结果:"+result); }
-
-
获取目标方法的异常
-
在表达式中加入
throwing = "ex",和上面一样,传入参数名称要一直,也要是ex,如:Throwable ex -
@AfterThrowing(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex") public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->异常通知,方法名:"+methodName+",异常:"+ex); }
-
切入点表达式使用
前置通知
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
public class LogAspect {// 设置切入点和通知类型@Before(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")public void beforeMethod(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs();System.out.println("Logger-->前置通知" + "参数:" + args[0] + "," + args[1]);}
}
后置通知
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
public class LogAspect {@After(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")public void afterMethod(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();// 方法名System.out.println("Logger-->后置通知,方法名:" + name);}
}
返回通知
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
public class LogAspect {@AfterReturning(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))", returning = "result")public void afterReturn(JoinPoint joinPoint, Object result) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:" + methodName + ",结果:" + result);}
}
异常通知
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
public class LogAspect {@AfterThrowing(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->异常通知,方法名:" + methodName + ",异常:" + ex);}
}
环绕通知
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
public class LogAspect {@Around(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());Object result = null;try {System.out.println("环绕通知-->目标对象方法执行之前");// 目标对象(连接点)方法的执行result = joinPoint.proceed();System.out.println("环绕通知-->目标对象方法返回值之后");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("环绕通知-->目标对象方法出现异常时");} finally {System.out.println("环绕通知-->目标对象方法执行完毕");}return result;}
}
重用切入点表达式
申明表达式
@Pointcut("execution(* com.atguigu.aop.annotation.*.*(..))")
public void pointCut(){}
在方法中使用
@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",参数:"+args);
}
在不同切面中使用
@Before("com.atguigu.aop.CommonPointCut.pointCut()")
public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",参数:"+args);
}

切面的优先级
相同目标方法上同时存在多个切面时,切面的优先级控制切面的内外嵌套顺序。
- 优先级高的切面:外面
- 优先级低的切面:里面
使用@Order注解可以控制切面的优先级:
- @Order(较小的数):优先级高
- @Order(较大的数):优先级低
将@Order注解放在切面类上而不是方法上!!!
- 优先级低的
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
@Order(4)
public class LogAspect {@After(value = "pointcut()")public void afterMethod2(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();// 方法名System.out.println("Logger-->后置通知 111111,方法名:" + name);}
}
- 优先级高的
@Aspect// 表示这个类是一个切面类
@Component// 注解保证这个切面类能够放入IOC容器
@Order(1)
public class NewLogAspect {@After(value = "com.example.aop.annoaop.LogAspect.pointcut()")public void afterMethod(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();// 方法名System.out.println("Logger-->后置通知 444444,方法名:" + name);}
}
效果
原先交换顺序后

没有交换顺序前

注解使用
使用AOP在方法或者接口上写上某些注解,完成特定方法。
实现思路
- 创建
@interface - 和上面一样要写
Aspect,并且要被spring管理 - 在方法或者接口上加上
@interface注解
实现示例
- 创建
@interface并命名为BunnyLog
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
// 加上这个注解打印当前时间
public @interface BunnyLog {}
-
使用AOP切面,需要注意的是:
-
如果只是单纯的加上注解,不考虑指定类或者类中方法,完成某些功能,要修改下面切入点
-
@Pointcut(value = "@annotation(com.example.aop.annoaop.BunnyLog)") public void bunnyPointcut() { }
-
-
如果想指定某些类或者某些方法下的
-
@Pointcut("execution(* com.example.aop.annoaop.*.*(..)) && @annotation(com.example.aop.annoaop.BunnyLog)") public void bunnyPointcut() { }
-
-
-
创建切面
@Aspect
@Component
public class BunnyAspect {/*** 切入点,并且加上了 @BunnyLog注解*/@Pointcut(value = "execution(* com.example.aop.annoaop.*.*(..)) || @annotation(com.example.aop.annoaop.BunnyLog)")public void bunnyPointcut() {}@Before("bunnyPointcut()")public void before(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();System.out.println("------AOP前置通知生效,方法名称------>" + name);LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyy年MM月dd日 HH:mm:ss");String format = localDateTime.format(timeFormatter);System.out.println("BunnyAspect,现在时间====>" + format);}
}
- 普通方法,需要在类上加上
@Component被spring管理,之后再方法中加上注解@BunnyLog
@Component
public class BunnyTestImpl {@BunnyLogpublic void method() {LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyy年MM月dd日 HH:mm:ss");String format = localDateTime.format(timeFormatter);System.out.println("测试方法,现在时间====>" + format);}
}
- 创建一个测试类
public class TestBefore {@Testpublic void test1() {ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");BunnyTestImpl bean = context.getBean(BunnyTestImpl.class);bean.method();}
}
执行结果:
r);
System.out.println(“测试方法,现在时间====>” + format);
}
}
- 创建一个测试类```java
public class TestBefore {@Testpublic void test1() {ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");BunnyTestImpl bean = context.getBean(BunnyTestImpl.class);bean.method();}
}
执行结果:
相关文章:
AOP切面编程,以及自定义注解实现切面
AOP切面编程 通知类型表达式重用表达式切面优先级使用注解开发,加上注解实现某些功能 简介 动态代理分为JDK动态代理和cglib动态代理当目标类有接口的情况使用JDK动态代理和cglib动态代理,没有接口时只能使用cglib动态代理JDK动态代理动态生成的代理类…...
C70600 CuNi10Fe1Mn铜合金深冲性能好
C70600 CuNi10Fe1Mn铜合金深冲性能好CW608N-R460、CW608N-H135、CuZn36Pb2As-R370、CuZn38Pb1-R460、CW607N-H120、CuZn38Pb1-H120、CW602N-H080、CW608N-H105、CuZn39Pb0.5-R460、CuZn39Pb0.5-H120、CW608N-H120、CuZn38Pb1-R470、CW607N-H080、CW607N-R470、CW607N-H105、CuZ…...
算法学习05:离散化、区间合并
算法学习05:离散化、区间合并 文章目录 算法学习05:离散化、区间合并前言需要记忆的模版:一、离散化1.例题:离散化 区间和:拓展: 二、区间合并(贪心)1.例题: 总结 前言 需要记忆的模…...
内部审计2.0时代:数字化工具和方法全面升级
文章目录 一、内部审计的发展阶段二、内部审计的逻辑架构三、内部审计数字化转型面临的问题(1)缺少内部审计数字化转型规划和方案(2)非结构化数据的采集和后续利用不足(3)依赖编程或使用新工具的数据分析能…...
五子棋小游戏(sut实验报告)
实验目的 实现人与人或人与电脑进行五子棋对弈 实验内容 启动游戏,显示游戏参数设置界面,用户输入参数后进入游戏界面,显示棋盘及双方博弈过程,游戏过程中可选择退出游戏。判定一方获胜后结束本局游戏,可选择继续下…...
图像超分辨率算法ESRGAN原理及应用
前言 图像超分辨率算法是一种用于增加图像分辨率的算法,与传统的图像缩放算法不同的是,超分算法在放大图像的同时根据原图纹理生成更多细节,确保图像在放大后仍然有清晰的纹理细节。 一、模型简介 1、模型开源地址 GitHub - xinntao/ESRGAN: ECCV18 Workshops - Enhance…...
excel 动态列导出
excel动态列,只好用poi来写了,也并不复杂,一样就这个件事情抽像为几步,就是套路了,开发效率就上去了。 1 准备空模板 导出操作与excel模板的导出一样,可以参考excel导出标准化 2 自定义SheetWriteHandler …...
Java零基础入门到精通_Day 1
01 Java 语言发展史 Java语言是美国Sun公司(StanfordUniversity Network)在1995年推出的 计算机语言Java之父:詹姆斯高斯林(ames Gosling) 重要的版本过度: 2004年 Java 5.0 2014年 Java 8.0 2018年 9月 Java 11.0 (目前所使用的) 02 J…...
Spring Cloud集成nacos配置中心
1.添加Nacos Config依赖 打开nacos-config-demo的pom.xml文件并添加以下两个依赖项 项目的配置文件中通常包括数据库连接配置项、日志输出配置项、Redis连接配置项、服务注册配置项等内容,如spring-cloud-alibaba-nacos-config-base-demo项目中就包含数据库连接配置…...
【AI视频教程】只需5步,AI作出鸡你太美视频
1.视频效果 2.准备工作 制作视频效果,需要准备下面3个条件: 准备stable diffusion的环境剪辑一段【鸡你太美】原版视频stable diffusion安装sd-webui-IS-NET-pro插件 2.1部署stable diffusion环境 这里还是建议大家用云平台部署stable diffusion&am…...
C# OpenCvSharp DNN FreeYOLO 密集行人检测
目录 效果 模型信息 项目 代码 下载 C# OpenCvSharp DNN FreeYOLO 密集行人检测 效果 模型信息 Inputs ------------------------- name:input tensor:Float[1, 3, 192, 320] --------------------------------------------------------------- …...
一次HW红初面试
一、描述外网打点的流程? 靶标确认、信息收集、漏洞探测、漏洞利用、权限获取。最终的目的是获取靶标的系统权限/关键数据。 在这个过程中,信息收集最为重要。掌握靶标情报越多,后续就会有更多的攻击方式去打点。比如:钓鱼邮件、…...
网络攻防中nginx安全配置,让木马上传后不能执行、让木马执行后看不到非网站目录文件、命令执行后权限不能过高
网络攻防中nginx安全配置,让木马上传后不能执行、让木马执行后看不到非网站目录文件、命令执行后权限不能过高。 0x01 Nginx介绍 nginx本身不能处理PHP,它只是个web服务器,当接收到请求后,如果是php请求,则发给php解释器处理,并把结果返回给客户端。nginx一般是把请求发…...
ctfshow web入门 php特性 web146-web150
1.web146 :被过滤了,三元运算符用不了,还可以用位运算符,逻辑运算符,等,逻辑运算符要注意或运算符的短路性 eval(return 1|phpinfo()|1) eval(return 1phpinfo()|1) payload: v11&v20&v3(~%8C%86%8C%8B%9A%92…...
Linux:kubernetes(k8s)prestop事件的使用(10)
他的作用是在结束pod容器之后进行的操作 apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型 metadata: # pod相关的元数据,用于描述pod的数据name: nginx-po # pod名称labels: # pod的标签type: app #这个是随便写的 自定义的标签version: 1.0.0 #这个…...
vue2【详解】生命周期(含父子组件的生命周期顺序)
1——beforeCreate:在内存中创建出vue实例,数据观测 (data observer) 和 event/watcher 事件配置还没调用(data 和 methods 属性还没初始化) 【执行数据观测 (data observer) 和 event/watcher 事件配置】 2——created…...
C++基础语法和概念
基本语法和数据类型 C 是一种高性能的编程语言,允许程序员对内存管理进行精细控制。了解 C 的基本语法和数据类型是学习这门语言的第一步。以下是一些基础概念的详细介绍: 基本语法 程序结构 一个基础的 C 程序通常包括一个或多个头文件引用、一个 m…...
Vue.js+SpringBoot开发海南旅游景点推荐系统
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统ÿ…...
mysql笔记:11. 性能优化
文章目录 概览查询速度优化1. 分析查询语句1.1 EXPLAIN1.2 DESCRIBE 2. 使用索引优化查询3. 优化子查询 数据库结构优化1. 分解表2. 建立中间表3. 增加冗余字段4. 优化插入速度4.1. MyISAM引擎表4.2. InnoDB引擎表 5. 分析表、检查表和优化表5.1. 分析表5.2. 检查表5.3. 优化表…...
基于Docker搭建Maven私服仓库(Linux)详细教程
文章目录 1. 下载镜像并启动容器2. 配置Nexus3. 配置本地Maven仓库 1. 下载镜像并启动容器 下载Nexus3镜像 docker pull sonatype/nexus3查看Nexus3镜像是否下载成功 docker images创建Nexus3的挂载文件夹 mkdir /usr/local/nexus-data && chown -R 200 /usr/local…...
SetDPI终极指南:如何精准控制Windows多显示器DPI缩放,告别模糊显示
SetDPI终极指南:如何精准控制Windows多显示器DPI缩放,告别模糊显示 【免费下载链接】SetDPI 项目地址: https://gitcode.com/gh_mirrors/se/SetDPI 你是否厌倦了Windows系统粗糙的DPI缩放设置?当你在4K显示器上享受清晰文字时&#x…...
C++ 常用算法模板整理【蓝桥杯】
文章目录前言一、基础数据结构与算法二、图论 / 搜索算法三、数论算法四、动态规划算法总结前言 为方便日常刷题与竞赛使用,本文整理了常用的 C 算法模板,基础算法、搜索、图论、数论及动态规划等核心内容。 一、基础数据结构与算法 1.求区间和&#x…...
保姆级教程:在RTX 4090上复现TVCG2024顶会论文PGSR(3D高斯表面重建)
在RTX 4090上实战复现PGSR:3D高斯表面重建的完整工程指南 当3D高斯抛雪球(3DGS)遇上几何约束,会碰撞出怎样的火花?ZJU-3DV团队发表在TVCG2024的PGSR论文,通过平面化高斯表示和几何正则化,在保持…...
SpringCloud微服务进阶-Nacos更加全能的注册中心疗
插件化架构 v3 版本最大的变化是引入了模块化插件系统。此前版本中集成在核心包里的原生功能,现在被拆分成独立的插件。 每个插件都是一个独立的 Composer 包,包含 Swift 和 Kotlin 代码、权限清单以及原生依赖。开发者只需安装实际用到的插件࿰…...
龙芯k - 走马观碑组MPU驱动移植芯
先回顾:三次握手(建立连接)核心流程(实际版) 为了让挥手流程衔接更顺畅,咱们先快速回顾三次握手的实际核心,避免上下文脱节: 第一步(客户端→服务器)…...
2026届毕业生推荐的十大降AI率工具推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 把文本原创性予以优化,要从多个维度去着手:对句式的结构开展巧妙的调…...
Qwen-Image-2512-Pixel-Art-LoRA 前端集成实战:Vue.js构建像素画在线创作工具
Qwen-Image-2512-Pixel-Art-LoRA 前端集成实战:Vue.js构建像素画在线创作工具 最近在捣鼓一些AI生成图片的玩法,发现像素画这个风格特别有意思。它那种复古、简洁又充满设计感的味道,在很多独立游戏、NFT艺术和社交媒体头像里都很受欢迎。不…...
前端团队协作:别让沟通成本拖垮你的项目
前端团队协作:别让沟通成本拖垮你的项目 什么是前端团队协作? 前端团队协作是指前端开发团队成员之间的协调与配合,包括代码管理、任务分配、沟通交流等方面。别以为前端开发只是写代码,团队协作不好,项目就会变成一场…...
WarcraftHelper完整指南:5步让魔兽争霸III在现代电脑上完美运行
WarcraftHelper完整指南:5步让魔兽争霸III在现代电脑上完美运行 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸III是一款经典的游…...
Android应用语言独立设置:打破系统语言束缚的终极解决方案
Android应用语言独立设置:打破系统语言束缚的终极解决方案 【免费下载链接】Language-Selector Language Selector let users select individual app languages (Android 13) 项目地址: https://gitcode.com/gh_mirrors/la/Language-Selector 你是否曾在多语…...
