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

AOP切面编程,以及自定义注解实现切面

AOP切面编程

  1. 通知类型
  2. 表达式
  3. 重用表达式
  4. 切面优先级
  5. 使用注解开发,加上注解实现某些功能

简介

  • 动态代理分为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在方法或者接口上写上某些注解,完成特定方法。

实现思路

  1. 创建@interface
  2. 和上面一样要写Aspect,并且要被spring管理
  3. 在方法或者接口上加上@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切面编程 通知类型表达式重用表达式切面优先级使用注解开发&#xff0c;加上注解实现某些功能 简介 动态代理分为JDK动态代理和cglib动态代理当目标类有接口的情况使用JDK动态代理和cglib动态代理&#xff0c;没有接口时只能使用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&#xff1a;离散化、区间合并 文章目录 算法学习05&#xff1a;离散化、区间合并前言需要记忆的模版&#xff1a;一、离散化1.例题&#xff1a;离散化 区间和&#xff1a;拓展: 二、区间合并&#xff08;贪心&#xff09;1.例题&#xff1a; 总结 前言 需要记忆的模…...

内部审计2.0时代:数字化工具和方法全面升级

文章目录 一、内部审计的发展阶段二、内部审计的逻辑架构三、内部审计数字化转型面临的问题&#xff08;1&#xff09;缺少内部审计数字化转型规划和方案&#xff08;2&#xff09;非结构化数据的采集和后续利用不足&#xff08;3&#xff09;依赖编程或使用新工具的数据分析能…...

五子棋小游戏(sut实验报告)

实验目的 实现人与人或人与电脑进行五子棋对弈 实验内容 启动游戏&#xff0c;显示游戏参数设置界面&#xff0c;用户输入参数后进入游戏界面&#xff0c;显示棋盘及双方博弈过程&#xff0c;游戏过程中可选择退出游戏。判定一方获胜后结束本局游戏&#xff0c;可选择继续下…...

图像超分辨率算法ESRGAN原理及应用

前言 图像超分辨率算法是一种用于增加图像分辨率的算法,与传统的图像缩放算法不同的是,超分算法在放大图像的同时根据原图纹理生成更多细节,确保图像在放大后仍然有清晰的纹理细节。 一、模型简介 1、模型开源地址 GitHub - xinntao/ESRGAN: ECCV18 Workshops - Enhance…...

excel 动态列导出

excel动态列&#xff0c;只好用poi来写了&#xff0c;也并不复杂&#xff0c;一样就这个件事情抽像为几步&#xff0c;就是套路了&#xff0c;开发效率就上去了。 1 准备空模板 导出操作与excel模板的导出一样&#xff0c;可以参考excel导出标准化 2 自定义SheetWriteHandler …...

Java零基础入门到精通_Day 1

01 Java 语言发展史 Java语言是美国Sun公司(StanfordUniversity Network)在1995年推出的 计算机语言Java之父:詹姆斯高斯林(ames Gosling) 重要的版本过度&#xff1a; 2004年 Java 5.0 2014年 Java 8.0 2018年 9月 Java 11.0 &#xff08;目前所使用的&#xff09; 02 J…...

Spring Cloud集成nacos配置中心

1.添加Nacos Config依赖 打开nacos-config-demo的pom.xml文件并添加以下两个依赖项 项目的配置文件中通常包括数据库连接配置项、日志输出配置项、Redis连接配置项、服务注册配置项等内容&#xff0c;如spring-cloud-alibaba-nacos-config-base-demo项目中就包含数据库连接配置…...

【AI视频教程】只需5步,AI作出鸡你太美视频

1.视频效果 2.准备工作 制作视频效果&#xff0c;需要准备下面3个条件&#xff1a; 准备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&#xff1a;input tensor&#xff1a;Float[1, 3, 192, 320] --------------------------------------------------------------- …...

一次HW红初面试

一、描述外网打点的流程&#xff1f; 靶标确认、信息收集、漏洞探测、漏洞利用、权限获取。最终的目的是获取靶标的系统权限/关键数据。 在这个过程中&#xff0c;信息收集最为重要。掌握靶标情报越多&#xff0c;后续就会有更多的攻击方式去打点。比如&#xff1a;钓鱼邮件、…...

网络攻防中nginx安全配置,让木马上传后不能执行、让木马执行后看不到非网站目录文件、命令执行后权限不能过高

网络攻防中nginx安全配置,让木马上传后不能执行、让木马执行后看不到非网站目录文件、命令执行后权限不能过高。 0x01 Nginx介绍 nginx本身不能处理PHP,它只是个web服务器,当接收到请求后,如果是php请求,则发给php解释器处理,并把结果返回给客户端。nginx一般是把请求发…...

ctfshow web入门 php特性 web146-web150

1.web146 :被过滤了&#xff0c;三元运算符用不了&#xff0c;还可以用位运算符&#xff0c;逻辑运算符,等&#xff0c;逻辑运算符要注意或运算符的短路性 eval(return 1|phpinfo()|1) eval(return 1phpinfo()|1) payload&#xff1a; v11&v20&v3(~%8C%86%8C%8B%9A%92…...

Linux:kubernetes(k8s)prestop事件的使用(10)

他的作用是在结束pod容器之后进行的操作 apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型 metadata: # pod相关的元数据&#xff0c;用于描述pod的数据name: nginx-po # pod名称labels: # pod的标签type: app #这个是随便写的 自定义的标签version: 1.0.0 #这个…...

vue2【详解】生命周期(含父子组件的生命周期顺序)

1——beforeCreate&#xff1a;在内存中创建出vue实例&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置还没调用&#xff08;data 和 methods 属性还没初始化&#xff09; 【执行数据观测 (data observer) 和 event/watcher 事件配置】 2——created&#xf…...

C++基础语法和概念

基本语法和数据类型 C 是一种高性能的编程语言&#xff0c;允许程序员对内存管理进行精细控制。了解 C 的基本语法和数据类型是学习这门语言的第一步。以下是一些基础概念的详细介绍&#xff1a; 基本语法 程序结构 一个基础的 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的海南旅游推荐系统&#xff…...

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…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

如何在Windows本机安装Python并确保与Python.NET兼容

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

OpenGL-什么是软OpenGL/软渲染/软光栅?

‌软OpenGL&#xff08;Software OpenGL&#xff09;‌或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式&#xff08;包括几何处理、光栅化、着色等&#xff09;&#xff0c;不依赖GPU硬件加速。这种模式通常性能较低&#xff0c;但兼容性极强&#xff0c;常用于不支持硬件加速…...