Springboot注解@Aspect(一)之@Aspect 作用和Aop关系详解

news2024/12/4 17:04:15

目录

@Aspect的使用

配置

作用

通知相关的注解

例子

结果:

@Aspect作用和Spring Aop关系

示例

标签表达式

@Aspect的使用

配置

        要启用 Spring AOP 和 @Aspect 注解,需要在 Spring 配置中启用 AspectJ 自动代理,但是在 Spring Boot 中,通常不需要显式地添加 @EnableAspectJAutoProxy,因为 Spring Boot 的自动配置特性已经包含了这一设置。:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // ...
}

         @Aspect 注解也要写@Component,或通过其他方式注册为 Spring Bean,以确保 Spring 容器能够识别并管理这个切面。

@Aspect
@Component
public class LoggingAspect {
}

作用

  1. 定义切面(Aspect)

    切面是跨多个类或对象的横切关注点的模块化。在 Spring AOP 中,切面是通过使用 @Aspect 注解的类来表示的。
  2. 切入点(Pointcut)

    使用 @Pointcut 注解来定义切入点表达式,指定切面应用的位置。切入点定义了切面应该在何处插入其横切逻辑,即切面应该应用的连接点(如方法执行)的集合。
  3. 通知(Advice)

  • 前置通知(Before advice):在某连接点(方法执行等)之前执行,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
  • 后置通知(After advice):在某连接点之后执行,无论该连接点是正常完成还是抛出异常。
  • 返回后通知(After-returning advice):在某连接点正常完成后执行。

  • 抛出异常后通知(After-throwing advice):如果方法抛出异常退出,则执行通知。

  • 环绕通知(Around advice):在方法调用之前和之后执行,它将决定是否继续执行连接点或直接返回自己的返回值或抛出异常。

通知相关的注解

  1.  @Around:环绕增强: 就是既可以前置增强,也可以后置增强。环绕通知会影响到AfterThrowing通知的运行,不要同时使用。
  2.  @Before:标识一个前置增强方法,

  3. @AfterReturning:后置增强,如无返回结果,此注解不会执行

  4. @After:final增强,不管是抛出异常或者正常退出都会执行

  5. @AfterThrowing: 异常抛出增强

例子

假设我们有一个服务类 SampleService,我们想在其方法执行的不同阶段添加日志。

public class SampleService {
    public void performAction() {
        System.out.println("Performing action in SampleService");
    }
}

现在,我们定义一个切面 LoggingAspect 来添加日志:

@Aspect
@Component
public class LoggingAspect {

    // 前置通知:在方法执行之前执行
    @Before("execution(* SampleService.performAction(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before executing: " + joinPoint.getSignature().getName());
    }

    // 后置通知:在方法执行之后执行(无论是否发生异常)
    @After("execution(* SampleService.performAction(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After executing: " + joinPoint.getSignature().getName());
    }

    // 返回后通知:在方法成功执行之后执行
    @AfterReturning("execution(* SampleService.performAction(..))")
    public void logAfterReturning(JoinPoint joinPoint) {
        System.out.println("After returning from: " + joinPoint.getSignature().getName());
    }

    // 异常后通知:在方法抛出异常后执行
    @AfterThrowing(pointcut = "execution(* SampleService.performAction(..))", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("After throwing in: " + joinPoint.getSignature().getName() + ", Exception: " + ex);
    }

    // 环绕通知:在方法执行之前和之后执行
    @Around("execution(* SampleService.performAction(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around before: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed(); // 继续执行方法
        System.out.println("Around after: " + joinPoint.getSignature().getName());
        return result;
    }
}
结果:

        就@Before来说,只要performAction方法被调用,那么第一步就是先执行这段代码:System.out.println("Before executing: " + joinPoint.getSignature().getName());执行完后在执行performAction方法。其他方法也是如此只是触发时机不同罢了。

@Aspect作用和Spring Aop关系

   @Aspect 是 AspectJ 框架中的一个注解,它是面向切面编程(AOP)的一个关键部分。AspectJ 是一个独立的 AOP 框架,而 Spring 框架(包括 Spring Boot)则集成了 AspectJ 的一部分功能,使得开发者可以在 Spring 应用中方便地使用 AOP。

        AOP 是一种编程范式(软件工程中的一类典型的编程风格。),用于增加程序的模块化,通过将横切关注点(如日志、安全、事务管理等)从业务逻辑中分离出来,提高代码的可重用性和可维护性。说白了其实我感觉就是动态代理,可以为相关方法前后等统一进行一些处理。

        Spring Boot 作为 Spring 框架的一个扩展,继承了 Spring 的 AOP 功能。在 Spring Boot 应用中,AOP 使用代理模式来实现 AOP,其中 @Aspect 注解的类被当作一个带有通知(Advice)和切入点(Pointcut)的切面。

        Spring AOP 使用代理模式来拦截对对象的方法调用。当在 Spring 应用中定义了 AOP 切面时,Spring 容器会为匹配切面指定的切入点的 Bean 创建一个代理对象。这个代理对象在调用原始方法之前或之后执行切面中定义的逻辑。

  • 动态代理:如果一个 Bean 至少实现了一个接口,Spring AOP 默认会使用 JDK 的动态代理来创建这个 Bean 的代理。
  • CGLIB 代理:如果一个 Bean 没有实现任何接口,Spring AOP 会使用 CGLIB 库来创建代理。

        虽然使用 @Aspect 注解和 @Before@After 等注解定义了切面的行为,但这些注解本身并不负责拦截方法调用。真正的方法拦截是由 Spring AOP 在背后通过动态代理机制来实现的。当方法被调用时,实际上是先调用代理对象的对应方法,代理对象再根据 AOP 配置来决定是否调用原始对象的方法,以及在调用前后执行哪些额外的逻辑。

示例

        假设有一个简单的服务类 MyService,我们想在其 performAction 方法执行前后添加日志:

public class MyService {
    public void performAction() {
        System.out.println("Performing action");
    }
}

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* MyService.performAction(..))")
    public void logBefore() {
        System.out.println("Before action");
    }

    @After("execution(* MyService.performAction(..))")
    public void logAfter() {
        System.out.println("After action");
    }
}

        在这里,LoggingAspect 定义了在 MyServiceperformAction 方法执行前后要执行的日志操作。但实际上,当 performAction 方法被调用时,它是通过 MyService 的代理来调用的,代理负责根据 LoggingAspect 的配置执行相应的 AOP 逻辑。

发现通知参数中的joinPoint不知道做什么用,请看我的下一章 Springboot注解@Aspect(二)JoinPoint 使用详解

标签表达式

        上述例子中你会好奇 @Before("execution(* SampleService.performAction(..))"),这中间的execution是什么意思后面括号内是什么意思。这其实是注解使用的标签表达式,有如下这些:

  • within:用于匹配指定类型内的方法执行

  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也* 类型匹配

  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配

  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法

  • @within:用于匹配所以持有指定注解类型内的方法

  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解,和@annotation区别是不用全路径

  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行

  • @annotation:用于匹配当前执行方法持有指定注解的方法

主要记住execution和@annotation用的比较多,一个是用在方法上一个是用在相关注解上

如何编写切入点表达式:

  • 匹配特定方法execution([权限加返回类型] [类路径].[方法名称]([参数]))

匹配带有特定注解的方法@annotation(com.example.MyAnnotation)

  • 匹配所有被 @MyAnnotation 注解的方法。

其中:

(..)代表所有参数

(*,String)代表第一个参数为任何值,第二个为String类型,

(..,String)代表最后一个参数是String类型

发现通知参数中的joinPoint不知道做什么用,请看我的下一章 Springboot注解@Aspect(二)JoinPoint 使用详解

------------------------------------------与正文内容无关------------------------------------
如果觉的文章写对各位读者老爷们有帮助的话,麻烦点赞加关注呗!作者在这拜谢了!

混口饭吃了!如果你需要Java 、Python毕设、商务合作、技术交流、就业指导、技术支持度过试用期。请在关注私信我,本人看到一定马上回复!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1412276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

shell脚本-函数及数组

一.函数 1.函数的作用 语句块定义成函数约等于别名,定义函数,再引用函数 封装的可重复利用的具有特定功能的代码 2.函数的基本格式 法一: [function] 函数名 {命令序列[return x] #使用return或者exit可以显式的结束函数 }法二&…

对比一下Confluence,其实HelpLook搭建知识库也不错

随着越来越多的企业转向远程工作和分散团队,寻找一种适合团队协作和知识共享的工具变得更为重要。HelpLook和Confluence是两个我认为比较相似的知识库软件,它们都提供了丰富的功能和卓越的用户体验。接下来就对HelpLook和Confluence进行详细的介绍和对比…

【Spring 篇】MyBatis DAO层实现:数据之舞的精灵

欢迎来到MyBatis DAO层的神奇世界,这里将为你揭示DAO层的奥秘,让你成为数据之舞的精灵。无论你是初学者还是想要深入了解DAO层的开发者,这篇博客将引导你踏入MyBatis DAO层的王国,一探其中的精彩。 舞台1:DAO层的角色…

【大数据面试题】HBase面试题附答案

目录 1.介绍下HBase 2.HBase优缺点 3.介绍下的HBase的架构 4.HBase的读写缓存 5.在删除HBase中的一个数据的时候,它是立马就把数据删除掉了吗? 6.HBase中的二级索引 7.HBase的RegionServer宕机以后怎么恢复的? 8.HBase的一个region由哪些东西组成? 9.…

安科瑞电化学储能电能管理系统解决方案——安科瑞赵嘉敏

1 概述 在我国新型电力系统中,新能源装机容量逐年提高,但是新能源比如光伏发电、风力发电是不稳定的能源,所以要维持电网稳定,促进新能源发电的消纳,储能将成为至关重要的一环,是分布式光伏、风电等新能源消…

LeetCode 40.组合总和 II

组合总和 II 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 方法一、回溯 由于题目要求解集…

第十九周周报

文章目录 摘要文献阅读DeepHuman: 3D Human Reconstruction from a Single Image(ICCV 2019)贡献摘要网络结构总结 PIFu: Pixel-Aligned Implicit Function for High-Resolution Clothed Human Digitization贡献摘要网络结构总结 Animated 3D human avatars from a single imag…

多项式乘法逆(p4238 NTT)

题目路径&#xff1a; https://www.luogu.com.cn/problem/P4238 思路&#xff1a; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<cstring> #include<cmath> #include<ctime> #include&l…

有什么办法可以让模糊的老照片变清晰?这几个方法收藏好!

照片盒子里的老照片&#xff0c;宛如一扇陈旧的时光之门&#xff0c;等着我们去开启。那些尘封的记忆&#xff0c;似乎已经被时间遗忘&#xff0c;但当我们轻轻拂去尘埃&#xff0c;那些熟悉的画面便再次浮现在眼前。然而&#xff0c;岁月无情&#xff0c;这些宝贵的瞬间在时间…

node.js漏洞总结

js开发的web应用和php/Java最大的区别就是js可以通过查看源代码的方式查看到编写的代码&#xff0c;但是php/Java的不能看到&#xff0c;也就是说js开发的web网页相当于可以进行白盒测试。 流行的js框架有&#xff1a; 1. AngularJS 2. React JS 3. Vue 4. jQuery 5. Backbone…

Linux | makefile简单教程 | Makefile的工作原理

前言 在学习完了Linux的基本操作之后&#xff0c;我们知道在linux中编写代码&#xff0c;编译代码都是要手动gcc命令&#xff0c;来执行这串代码的。 但是我们难道在以后运行代码的时候&#xff0c;难道都要自己敲gcc命令嘛&#xff1f;这是不是有点太烦了&#xff1f; 在vs中…

Docker安装多个nginx容器时,要注意端口设置:

Docker安装多个nginx容器时&#xff0c;要注意端口设置&#xff1a; docker run -id --namemynginx4 -p 8089:80 nginx 安装多个nginx容器时&#xff0c;要注意端口设置&#xff1a;宿主机80端口已经被暂用&#xff0c;所以宿主机端口一定不能设置位80&#xff0c;但是容器上80…

Vulnhub靶场DC-7

本机192.168.223.128 目标192.168.223.136 主机发现 nmap -sP 192.168.223.0/24 端口发现 nmap -sV -p- -A 192.168.223.136 开启了22 80端口 80端口apache服务 先进入web界面看一下 提示&#xff1a;DC7加了一些新的东西&#xff0c;让我看看盒子之外的东西&#xff0c;与…

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

C 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层 一.容器适配器的介绍二.利用容器适配器实现栈和队列1.stack2.queue 三.仿函数介绍1.什么是仿函数2.仿函数的使用3.函数指针的使用1.函数指针的用处2.利用函数指针完成回调3.利用仿函数完成回…

docker 体验怀旧游戏(魂斗罗等)

docker run --restart always -p 8081:80 --name fc-games -d registry.cn-hangzhou.aliyuncs.com/bystart/fc-games:latest ip:8081访问 jsnes: js制作了一个网页版的NES模拟&#xff0c;可以在网页上玩fc游戏 (gitee.com)

创建第一个 Spring 项目(IDEA社区版)

文章目录 创建 Spring 项目创建一个普通的 Maven 项目添加 Spring 依赖IDEA更换国内源 运行第一个 Spring 项目新建启动类存储 Bean 对象将Bean注册到Spring 获取并使用 Bean 对象 创建 Spring 项目 创建一个普通的 Maven 项目 首先创建一个普通的 Maven 项目 添加 Spring 依…

Tomcat好帮手---JDK

目录 1、Tomcat好帮手---JDK 2、安装JDK 部署Tomcat参考博主博客 部署TOMCAT详解-CSDN博客 1、Tomcat好帮手---JDK JDK是 Java 语言的软件开发工具包&#xff0c;JDK是整个java开发的核心&#xff0c;它包含了JAVA的运行环境&#xff08;JVMJava系统类库&#xff09;和JAVA…

2024年新提出的算法:一种新的基于数学的优化算法——牛顿-拉夫森优化算法|Newton-Raphson-based optimizer,NRBO

1、简介 开发了一种新的元启发式算法——Newton-Raphson-Based优化器&#xff08;NRBO&#xff09;。NRBO受到Newton-Raphson方法的启发&#xff0c;它使用两个规则&#xff1a;Newton-Raphson搜索规则&#xff08;NRSR&#xff09;和Trap Avoidance算子&#xff08;TAO&#…

视频压缩怎么才能保持画质清晰?这样设置参数~

很多时候我们都需要压缩视频&#xff0c;但在减小视频大小的时候我们也会担心画质清晰度问题&#xff0c;那怎么既能压缩视频大小&#xff0c;又能保证视频清晰度呢&#xff1f;下面就来了解下吧~ 视频压缩分为无损压缩和有损压缩&#xff0c;如果想保持画质清晰&#xff0c;可…

[C#]winform部署yolov5实例分割模型onnx

【官方框架地址】 https://github.com/ultralytics/yolov5 【算法介绍】 YOLOv5实例分割是目标检测算法的一个变种&#xff0c;主要用于识别和分割图像中的多个物体。它是在YOLOv5的基础上&#xff0c;通过添加一个实例分割模块来实现的。 在实例分割中&#xff0c;算法不仅…