【Spring AOP学习】AOP的组成 SpringAOP的实现和实现原理

news2024/11/16 4:40:03

目录

一、认识SpringAOP

1、AOP是什么?

2、AOP的功能

3、AOP的组成(重要)

二、SpringAOP的实现

🌷1、添加Spring AOP框架支持

🌷2、定义切面和切点

🌷 3、定义通知

3.1 完成代码实现

3.2 具体通知分析

🌷4、小练习:使用AOP统计UserController每个方法的执行时间。

 三、SpringAOP的实现原理(重点)


一、认识SpringAOP

🌷1、AOP是什么?

        AOP是一个思想Spring AOP 是⼀个框架,是对 AOP 思想的实现,它们的关系和IoC 与 DI 类似。OOP是面向对象编程。AOP:面向切面编程:对某一类事情的集中处理(也就是同一类的事务怎么处理)。

栗子:

        比如CSDN:编辑博客,删除博客,写博客都要在用户登录的基础上实现,所以在都实现单个的功能之前,都要对用户登录信息进行验证,各自实现或者调用用户验证的方法,所以非常麻烦。那么抽取成一个公共方法也可以:但是当对公共方法的参数或者其他进行了修改,那么它的所有调用方都要进行修改。所以对于这种功能统⼀,且使⽤的地⽅较多的功能,就可以考虑 AOP来统⼀处理了。所以现在AOP就是:这是哪个功能都要实现的是相同的功能,我们可以将它理解为就是对一类事情的集中处理,现在只需要在某一处配置一下就好了,此时所有需要时判断用户登录的方法就可以全部实现用户登录验证了。

🌷2、AOP的功能

(1)统⼀⽇志记录
(2)统⼀⽅法执⾏时间统计:项目监控、监控项目请求流量、监控接口的响应时间,甚至每个方法的响应时间;
(3)统⼀的返回格式设置:http状态码、code(业务状态码:后端处理响应成功,不代表业务办理成功)、msg(业务处理失败,返回的信息)、data;
(4)统⼀的异常处理;
(5)事务的开启和提交等。


注意:使⽤ AOP 可以扩充多个对象的某个能⼒,所以 AOP 可以说是 OOP(Object Oriented Programming,⾯向对象编程)的补充和完善

 🌷3、AOP的组成(重要)

        比如我们上面举的例子:关于csdn的博客的整个过程就是一个切面:其中:写博客功能、删除博客、编辑博客都是连接点,它们三个都要实现一个用户登录功能的校验,这个用户登录功能就是一个切点,其中用户登录功能中的方法体中实现代码就是一个通知。


二、SpringAOP的实现(重要)

目标:我们就实现上图中的关于csdn的博客的这个AOP的实现。我们使用SpringAOP来实现AOP的功能,目的是拦截所有UserController方法,每次调用UerController中的任何一个方法的时候,都执行相应的通知事件。

SpringAOP的实现步骤如下:

(1)添加SpringAOP的框架支持;

(2)定义切面和切点;

(3)定义通知。

🌷1、添加Spring AOP框架支持

在 pom.xml 中添加如下配置:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

🌷2、定义切面和切点

//表示是一个切面:CSDN
@Component
@Slf4j
//表示是一个切面:CSDN,要结合五大注解使用
@Aspect
public class LoginAspect {
    //表示是一个切点:登录功能验证
    @Pointcut("execution(* aop.controller.UserController.*(..))")
    public void pointcut1(){
        //方法体就是通知
    }
}

🍑总结 :

        切点指的是具体要处理的某一类问题:用户登录权限的验证就是一个具体的问题,也就是一个切点。

(1)切面上要加@Aspect注解,结合五大注解使用:加@Component;

(2)切点: pointcut 方法为空方法,它不需要有方法体,此方法名就是起到⼀个“标识”的作用,标识下面的通知方法具体指的是哪个切点(因为切点可能有很多个)。

(3)一个@Aspect(切面)下可以有多个切点,@Pointcut("execution(* aop.controller.UserController.*(..))")。同时通知方法不是一定要全部存在的。

(4)切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)

切点表达式说明:

(1)灰色表示可以省略,红色不能省略;

(2)修饰符是public等,其中*表示任意;

(3)返回值:*表示任意;

(4)包名:

com.example       表示固定包

com.example.*.service   表示example包下任意包下的固定目录service

com.example..     表示example包下所有的子包(含自己)

com.example.*.service..   表示example包下任意子包下固定目录service下的任意包。

(5)类

UserController   表示指定类

*Impl     表示以Impl结尾

User*    表示以User开头

*      表示任意

(6)方法名

writeBlog  固定方法

write*  表示以write开头

*Blog   表示以Blog结尾

* 表示任意

(7)参数

()  表示无参

(int)表示一个整型

(int,int)表示两个整型

(..)表示参数任意

(8)异常:throws一般不写

AspectJ ⽀持三种通配符
(1)* 表示匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)
(2).. 表示匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。
(3)+ 表示表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的所有⼦类包括本身。


比如:

execution(* com.cad.demo.User.*(..)) :匹配 User 类里的所有方法。
execution(* com.cad.demo.User+.*(..)) :匹配该类的子类包括该类的所有方法。
execution(* com.cad.*.*(..)) :匹配 com.cad 包下的所有类的所有方法。
execution(* com.cad..*.*(..)) :匹配 com.cad 包下、方法包下所有类的所有⽅法。
execution(* addUser(String, int)) :匹配 addUser 方法,且第⼀个参数类型是 String,第⼆个参数类型是 int。

🌷 3、定义通知

通知定义的是被拦截的方法(具体的写博客、编辑博客和删除博客)具体要执行的业务(用户登录权限的校验)。
使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
(1)前置通知使用@Before:通知方法会在目标方法调用之前执行。
(2)后置通知使用@After:通知方法会在目标方法返回或者抛出异常后调用。
(3)返回之后通知使用@AfterReturning:通知方法会在目标方法返回后调用。
(4)抛异常后通知使用@AfterThrowing:通知方法会在目标方法抛出异常后调用。
(5)环绕通知使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

3.1 完成代码实现

UserController文件

@Slf4j
@RequestMapping("/aop")
@RestController
public class UserController {
    //模拟写博客
    @RequestMapping("/writeBlog")
    public String writeBlog(){
        //模拟异常
//        int a = 10/0;
        log.info("write blog success...");
        return "write blog success...";
    }
    //编辑博客
    @RequestMapping("/editBlog")
    public String editBlog(){
        log.info("edit blog success...");
        return "edit blog success...";
    }
    //删除博客
    @RequestMapping("/deleteBlog")
    public String deleteBlog(){
        log.info("deleteBlog success...");
        return "deleteBlog success...";
    }
}

 LoginAspect文件


@Component
@Slf4j
//表示是一个切面:CSDN,要结合五大注解使用
@Aspect
public class LoginAspect {
    //表示是一个切点:登录功能验证
    @Pointcut("execution(* aop.controller.UserController.*(..))")
    public void pointcut1(){ }
    //1、前置通知使用@Before:通知方法会在目标方法调用之前执行。
    @Before("pointcut1()")
    public void doBefore(){
        log.info("do before...");
    }
    //2、后置函数@After
    @After("pointcut1()")
    public void doAfter(){
        log.info("do After...");
    }

    //3、@AfterReturning 在return 之前通知
    @AfterReturning("pointcut1()")
    public void doAfterReturning(){
        log.info("do doAfterReturning...");
    }

    //4、@doAfterThrowing 在return 之前通知
    @AfterThrowing("pointcut1()")
    public void doAfterThrowing(){
        log.info("do doAfterThrowing...");
    }

    //5、@doAround 环绕方法
    @Around("pointcut1()")
    //环绕方法要写返回结果  //ProceedingJoinPoint joinPoint表示连接点
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object object = null;
        log.info("环绕通知执行之前执行的方法...");
        //执行目标方法
        try {
            object = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        log.info("环绕通知执行之后执行的方法...");
        return object;
    }


    @Pointcut("execution(* aop.controller.UserController1.*(..))")
        public void pointcut2(){ }
}

3.2 具体通知分析

(1)@Before

@Before在具体的目标方法调用之前执行。

测试UserController类中的三个方法都成功:比如 

 2、@After

@After在具体调用目标方法之后执行;

(3)@AfterReturing

使用@AfterReturing会在目标方法return之前通知,知道@AfterReturing在@After之前执行;

(4)@AfterThrowing

🍑总结

         @doAfterThrowing只有在异常的时候才会执行,正常返回不会执行。异常情况@doAfterThrowing执行之后,@doAfterReturning就不会执行了。正常返回的时候执行@doAfterReturning,出现异常就不会执行了。

正常情况:

 异常情况:

(5)@Around(最常用)

🍑注意:

        先执行环绕通知,再执行前置通知,接着是目标方法,然后是doAfterReturing和do After后置通知。

  • getSignature()) //获取修饰符+ 包名+组件名(类名) +方法名
  • getSignature().getName()) //获取方法名
  • getSignature().getDeclaringTypeName()) //获取包名+组件名(类名)

🌷4、小练习:使用AOP统计UserController每个方法的执行时间。

普通写法:

在UserController中的每个方法都按如下计算:缺点是所有的方法(包括writeBlog,editBlog方法)都要写一下,冗余性很高。

AOP的写法

 /**
     * 计算UserController中所有方法的Log的执行时间
     */
    //表示是一个切点:登录功能验证
    @Pointcut("execution(* aop.controller.UserController.*(..))")
    public void pointcut2(){ }
    //@doAround 环绕方法
    @Around("pointcut2()")
    //环绕方法要写返回结果
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object object = null;
        long start = System.currentTimeMillis();
        //执行目标方法
        try {
            object = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        //getSignature()) //获取修饰符+ 包名+组件名(类名) +方法名
        log.info(joinPoint.getSignature().toLongString()+"耗时"+(System.currentTimeMillis()-start));
        return object;
    }

测试结果:

 时间不同主要是cpu调度的偏差。


 三、SpringAOP的实现原理(重点)


简单了解代理模式~https://mp.csdn.net/mp_blog/creation/editor/131963215

🍑总结:

(1)SpringAOP是构建在动态代理的基础上,所以Spring对AOP的支持局限于方法级别的拦截。

(2)Spring AOP支持JDK Proxy和 CGLIB的方式实现动态代理;

(3)proxyTargetClass为false,目标实现了接口,AOP默认会基于JDK的方式生成代理类;

(4)proxyTargetClass为false,没有实现接口的类,AOP会基于CGLIB的方式生成代理类;

(5)proxyTargetClass为false为true,AOP会基于CGLIB的方式生成代理类。


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

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

相关文章

目前可以实现用手机操作水质自动采样器吗

利用自动采样器进行水样采集可以说节省很大的人力物力&#xff0c;但是有时为了采到更具代表性的水样&#xff0c;我们需要对沟渠、深井、排污口等特殊场景进行采样。像这些狭小的空间领域采样就有点困难&#xff0c;对现场工作人员就带来了一些难题。所以也需要一款可以在井下…

HCIP——OSPF的防环机制

OSPF的防环机制 一、域间防环二、域内防环有向图转化1、有向图的画法2、示例&#xff1a; 三、SPF算法 OSPF将整个OSPF域划分为多个区域&#xff0c;区域内部通过拓扑信息计算路由&#xff0c;区域间传递路由信息&#xff0c;实现全网可达。OSPF防环机制主要是体现在域内防环和…

python3GUI--我的二维码生成工具By:PyQt5(附UI源码)

文章目录 一&#xff0e;前言二&#xff0e;展示1.主界面2.主界面-选择颜色&#xff08;动图&#xff09;3.主界面-选择样式&#xff08;动图&#xff09; 三&#xff0e;思路1.UI设计2.核心3.其他1.为什么调整了样式左侧二维码就跟着变化2.首次启动软件生成的文件哪里来的3.作…

华为8月8日将推出系统云翻新功能:P40/Mate 30系列首发

7月28日消息&#xff0c;7月28日消息&#xff0c;华为终端公司近日在微博上发布重要公告&#xff0c;宣布将于8月8日推出全新的系统云翻新功能。据悉&#xff0c;该功能将首次应用于华为 P40 系列手机和 Mate30 系列手机&#xff0c;为用户提供更便捷的手机数据备份和恢复体验。…

如何降低机场人员定位系统成本?哪种方案简单又好用?

一、方案简介 机场是一个室内空间巨大的人员聚集地差旅人员找不到出入口、卫生间、商铺为找检票口而误车等是很常见的现状。面对这些问题&#xff0c;机场信息数字化建设成为一种最为有效的解决方式&#xff01; 华安联大通过多技术融合实现室内外位置健全&#xff0c;推出一…

【机密计算-大厂有话说】微软 Azure

什么是机密计算&#xff1f; 机密计算是由机密计算联盟 (CCC) 定义的一个行业术语&#xff0c;CCC 是专注于定义并加速机密计算落地的基金会。 CCC 给机密计算的定义是&#xff1a;通过在基于硬件的可信执行环境 (TEE) 中执行计算来保护使用中的数据。 TEE 是是一个只能执行授权…

Jetbrains idea 代码关闭 注释自动渲染 导致换行不生效

方法1 关闭注释自动渲染 取消勾选 方法2 结尾使用 <br> 强制换行

【Python】logging模块笔记

目录 日志级别 四个组件 记录器 处理器 处理器 格式化器 格式 用法1&#xff1a;小项目可以采用编程的方法 用法2&#xff1a;建议采用配置文件的方式 用法3&#xff1a; 字典配置 日志级别 #默认的日志输出为warning # 使用baseConfig() 来指定日志输出级别 # 同时&#x…

每日一题——找到消失的数字

找到消失的数字 题目链接 思路 一个长度为n的数组中所有数据的范围在[1,n]内&#xff0c;题目要求我们找出在[1,n]范围内&#xff0c;但数组中没有出现的数字 如果可以使用额外空间&#xff0c;那这题就好办了。我们直接创建一个相同大小的数组&#xff0c;数组的每个位置代…

三. 多传感器标定方案(空间同步)--2

前面的内容&#xff1a; 一. 器件选型心得&#xff08;系统设计&#xff09;--1_goldqiu的博客-CSDN博客 一. 器件选型心得&#xff08;系统设计&#xff09;--2_goldqiu的博客-CSDN博客 二. 多传感器时间同步方案&#xff08;时序闭环&#xff09;--1 三. 多传感器标定方案…

AI聊天GPT三步上篮!

1、是什么&#xff1f; CHATGPT是OpenAI开发的基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构的聊天型人工智能模型。也就是你问它答&#xff0c;根据网络抓去训练 2、怎么用&#xff1f; 清晰表达自己诉求&#xff0c;因为它就是一个AI助手&#…

【腾讯云 Cloud Studio 实战训练营】Cloud Studio实现健康上报小程序(代码开源)

目录 &#x1f373;前言&#x1f373;实验介绍&#x1f373;产品介绍&#x1f373;注册Cloud Stdio&#x1f373;后端Spring服务&#x1f373;创建项目上传项目数据库连接与导入 &#x1f373;Vue后台管理创建项目编辑模板信息选择环境镜像上传资源文件 &#x1f373;小程序⭐总…

容器演进时间轴及容器技术演进

1.1 1979年 — chroot 容器技术的概念可以追溯到1979年的UNIX chroot。 它是一套“UNIX操作系统”系统&#xff0c;旨在将其root目录及其它子目录变更至文件系统内的新位置&#xff0c;且只接受特定进程的访问。 这项功能的设计目的在于为每个进程提供一套隔离化磁盘空间。 …

NIM游戏/SG函数

NIM游戏 先看一下一维 NIM游戏。 有一堆大小为 n 的石子&#xff0c;甲和乙轮流从石堆里面拿石子&#xff0c;不能一次拿掉所有石子&#xff0c;取走最后一个石子的人获胜&#xff0c;甲先开始&#xff0c;谁是必胜的&#xff1f; 显然&#xff0c;谁先手&#xff0c;谁就获胜…

蓝桥杯单片机第五届国赛 真题+代码

onewire.c /* # 单总线代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础&#xff0c;根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求&#xff0c;进行代码调试和修改。 */// #include …

Opencv的Mat内容学习

来源&#xff1a;Opencv的Mat内容小记 - 知乎 (zhihu.com) 1.Mat是一种图像容器&#xff0c;是二维向量。 灰度图的Mat一般存放<uchar>类型 RGB彩色图像一般存放<Vec3b>类型。 (1)单通道灰度图数据存放样式&#xff1a; (2)RGB三通道彩色图存放形式不同&#x…

微服务性能分析工具 Pyroscope 初体验

Go 自带接口性能分析工具 pprof&#xff0c;较为常用的有以下 4 种分析&#xff1a; CPU Profiling: CPU 分析&#xff0c;按照一定的频率采集所监听的应用程序 CPU&#xff08;含寄存器&#xff09;的使用情况&#xff0c;可确定应用程序在主动消耗 CPU 周期时花费时间的位置…

数值线性代数:奇异值分解SVD

本文记录计算矩阵奇异值分解SVD的原理与流程。 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。 零、预修 0.1 矩阵的奇异值 设列满秩矩阵&#xff0c;若的特征值为&#xff0c;则称为矩阵的奇异值。 0.2 SVD(分解)定理 设&#xff0c;则…

❤ Redirected when going from “/login“ to “/“ via a navigation guard错误

❤ vue路由遇到 Redirected when going from “/login“ to “/“ via a navigation guard错误 路由版本&#xff1a;“vue-router”: “^3.5.2”, 添加了路由守卫&#xff0c;然后开始报这个错误&#xff0c; 原因 就是路由版本导致的 解决办法 // 导航守卫限制路由跳转 …

Jenkins插件管理切换国内源地址

一、替换国内插件下载地址 选择系统管理–>插件管理–> Available Plugins 并等待页面完全加载完成、这样做是为了把jenkins官方的插件列表下载到本地、接着修改地址文件、替换为国内插件地址 进入插件文件目录 cd /var/lib/jenkins/updatesdefault.json 为插件源地址…