Spring AOP 简介

news2024/11/29 2:37:27

一、Spring AOP

AOP 是一种思想,而 Spring AOP 是一个框架,提供了一种对 AOP 思想的实现。

1、什么是 AOP?

AOP(Aspect Oriented Programming):是一种编程思想,表示面向切面编程。指的是对某一类事情的集中处理

举一个常见的例子,当我们实现用户登录校验的时候,如果有多个网页都有同样的需求,那么我们传统的写法是在每个页面都写一个校验逻辑,这就会导致代码的可维护性降低。而如果我们使用
AOP 的思想,就可以对这种功能一致,且多次使用的功能进行统一的处理。

通过上面的例子,我们可以归纳出 AOP 的应用场景:

  • 统一的用户登录判断
  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等

对于 AOP 来说,它可以扩充多个对象的某个能力,因此通常认为 AOP 是 OOP(Object Oriented Programming,面向对象编程)的补充和完善。

2、AOP 的组成

切面(Aspect):定义的是事件,描述了当前 AOP 的作用。是包含了 切点和通知 的类。例如定义当前AOP是进行统一用户登录判断的。

连接点(Join Point):连接点是在应用程序执行过程中可以插入切面的点,切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。典型的连接点包括方法调用、方法执行、异常抛出等。

切点(Pointcut):定义匹配 Join Point 的规则,给满足规则的 Join Point 添加 Advice。例如定义哪些接口判断用户登录权限,哪些不判断。

通知(Advice):AOP 执行方法的具体实现 。例如通过获取用户的 session 信息,判断用户登录状态。

在Spring AOP 中提供了以下五种类型的通知:

  1. 前置通知(@Before):通知方法会在目标方法调用之前执行。
  2. 后置通知(@After):通知方法会在目标方法返回或者抛出异常后调用。
  3. 返回通知(@AfterReturning):通知方法会在目标方法返回后调用。
  4. 异常通知(@AfterThrowing):通知方法会在目标方法抛出异常后调用。
  5. 环绕通知(@Around):通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

二、Spring AOP 实现

下面我们使用 Spring AOP 来完成拦截所有 UserController 里的方法,每次调用 UserController 中任意一个方法时,都执行相应的通知事件。

1、添加 AOP 框架支持

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、定义切面类

定义切面使用的是 @Aspect

@Aspect
@Component
public class UserAspect {

}

3、定义切点

定义切点使用 @Pointcut 注解,可在参数中定义匹配 Joint Point 的规则(这里使用的是 AspectJ 语法)

@Aspect
@Component
public class UserAspect {

    // 定义切点,使用 AspectJ 语法
    // 该切点规则将匹配 com.example.demo.controller.UserController 类
    // 中的所有方法,无论方法的返回类型和参数列表如何
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointCut(){}
}

4、实现通知

对于 前置通知、后置通知、返回通知、异常通知 的实现都如出一辙,并且非常简单,只需要添加给通知方法添加响应通知注解即可:

@Aspect
@Component
public class UserAspect {

    // 定义切点,使用 AspectJ 语法
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointCut(){}

    // 前置通知
    @Before("pointCut()")
    public void doBefore(){
        System.out.println("执行doBefore()前置通知!");
    }
    // 后置通知
    @After("pointCut()")
    public void doAfter(){
        System.out.println("执行doAfter()后置通知!");
    }
    // 返回通知
    @AfterReturning("pointCut()")
    public void doAfterReturn(){
        System.out.println("执行doAfterReturn()了返回通知");
    }
    // 异常通知
    @AfterThrowing("pointCut()")
    public void doAfterThrowing(){
        System.out.println("执行了doAfterThrowing()异常通知");
    }
    
}

比较复杂的是环回通知的实现,环回通知有它固定的格式:

@Aspect
@Component
public class UserAspect {
    // 定义切点,使用 AspectJ 语法
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointCut() {
    }
    // 环绕通知
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around ⽅法开始执⾏");
        // 执行目标方法
        Object obj = joinPoint.proceed();
        System.out.println("Around ⽅法结束执⾏");
        return obj;
    }
}

其中 ProceedingJoinPoint 在环绕通知中可以控制目标方法的执行。通过调用 joinPoint.proceed() 可以触发目标方法的执行。如果目标方法有返回值,当目标方法执行完毕后,它会被保存在 obj 变量中,作为整个环绕通知方法的返回值返回给调用方。

调用 UserController 中的方法,得到测试结果:

三、Spring AOP 实现原理

Spring AOP 是构建在动态代理基础上的。Spring 的切面是由包裹了目标对象的代理实现的,代理类处理方法的调用,执行额外的切面逻辑,并调用目标方法。

Spring AOP 支持 JDK Proxy 动态代理和 CGLIB 动态代理技术,它们主要有以下区别:

  1. JDK Proxy 来自于 Java 本身,CGLIB 来自于第三方。
  2. JDK Proxy 动态代理是基于接口的,要求代理类必须实现接口才能实现代理;CGLIB 动态代理是基于类的,通过继承被代理类完成动态代理,因此要求被代理类不能是 final 修饰的类。
  3. 在 JDK 8 以上的版本中,JDK Proxy 动态代理做了专门的优化,所以性能比 CGLIB 高。

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

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

相关文章

<Vue>使用依赖注入的方式共享数据

什么是vue依赖注入&#xff1f; Vue是一个用于构建用户界面的渐进式框架。 它提供了一种简单而灵活的方式来管理组件之间的数据流&#xff0c;即依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;。 依赖注入是一种设计模式&#xff0c;它允许一个组件从另一…

【数组】有序数组的平方

## 977.有序数组的平方 力扣题目链接 (opens new window) 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10]输出&#xff1a;[0,…

升级Python版本后,anaconda navigator启动失败

anaconda navigator启动失败&#xff0c;尤其是重装不解决问题的&#xff0c;大概率是库冲突 1.通过anaconda-navigator的图标启动&#xff0c;没有反应 2.在命令窗口&#xff0c;输入anaconda-navigator&#xff0c;报错如下 anaconda-navigator 3.错误来自这里 File &quo…

基于单片机的胎压监测系统的设计

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、系统整体设计方案二、 系统设计4.1 主流程图 三 系统仿真5.1 系统仿真调试实物 四、 结论 概要 本文以STC89C52单片机为控制核心&#xff0c;通过气压传感器模块对汽车各轮胎的胎压进行实时数据的采集与处理&…

AD教程 (七)元件的放置

AD教程 &#xff08;七&#xff09;元件的放置 第一种放置方法 点击右下角Panels&#xff0c;选择SCH Library&#xff0c;调出原理图库器件列表选中想要放置的元件&#xff0c;点击放置&#xff0c;就会自动跳转到原理图&#xff0c;然后放置即可这种方法需要不断打开元件库…

【源码解析】Spring Bean定义常见错误

案例1 隐式扫描不到Bean的定义 RestController public class HelloWorldController {RequestMapping(path "/hiii",method RequestMethod.GET)public String hi() {return "hi hellowrd";}}SpringBootApplication RestController public class Applicati…

立创eda专业版学习笔记(7)(阻焊开窗)

阻焊开窗是什么&#xff1f; 在介绍阻焊开窗之前&#xff0c;我们首先要知道阻焊层是什么。阻焊层是指印刷电路板子上要上油墨的部分&#xff0c;用于覆盖走线和敷铜&#xff0c;以保护PCB上的金属元素和防止短路。阻焊开窗是指在阻焊层上开一个口&#xff0c;以便在开口的位置…

前馈神经网络自动梯度计算和预定义算子

目录 1 自动梯度计算和预定义算子 1.1 利用预定义算子重新实现前馈神经网络 1.2 完善Runner类 1.3 模型训练 1.4 性能评价 1.5 增加一个3个神经元的隐藏层&#xff0c;再次实现二分类&#xff0c;并与1.1.1做对比. 1.6 自定义隐藏层层数和每个隐藏层中的神经元个数&#xf…

【网络安全技术】公钥密码体制

一、两种基本模型 1.加密模型 A要给B发信息&#xff0c;那就拿B的公钥加密&#xff0c;传给B&#xff0c;B收到后会拿他自己的私钥解密得到明文。 2.认证模型&#xff08;数字签名&#xff09; A用自己的私钥加密&#xff0c;传输之后&#xff0c;别人拿A的公钥解密&#xff…

IMU漂移相关

个人对IMU的漂移一直以来都很困惑&#xff0c;总结整理了这些材料&#xff0c;希望能理清楚一点思路。 总的来讲&#xff0c;IMU的漂移可建模为三部分&#xff0c;随机常值相关漂移白噪声&#xff0c; 但实际使用时&#xff0c;三者都出现的用法很少。严恭敏老师在博客中有相关…

cp没有--exclude选项!Linux复制文件夹时如何排除一些文件?

之前使用tar命令压缩文件将时&#xff0c;使用了–exclude选项排除了一些不需要的文件。现在我想复制一个文件夹&#xff0c;但是其中一些文件不需要复制&#xff0c;此时注意到cp命令居然没有–exclude选项。 rsync可以快速地帮助我们完成相同的事情&#xff0c;命令如下&…

Android Framework学习之Activity启动原理

Android Activity启动原理 Android 13.0 Activity启动原理逻辑流程图如下&#xff1a;

排序——选择排序

基本思想 每一趟在待排序元素中选取关键字最小的元素加入有序子序列。 算法代码 #include <iostream> using namespace std;//选择排序 void SelectSort(int nums[],int n){int i,j,min;for(i0;i<n-1;i){ //一共需要进行 n-1 趟 mini; //记录最小元素的下…

RK3566上运行yolov5模型进行图像识别

一、简介 本文记录了依靠RK官网的文档&#xff0c;一步步搭建环境到最终在rk3566上把yolov5 模型跑起来。最终实现的效果如下&#xff1a; 在rk3566 板端运行如下app&#xff1a; ./rknn_yolov5_demo model/RK356X/yolov5s-640-640.rknn model/bus.jpg其中yolov5s-640-640.r…

【GEE】​3、 栅格遥感影像波段特征及渲染可视化

1、简介 在本单元中&#xff0c;将学习以下内容&#xff1a; 使用遥感传感器捕获的不同类型的能量。如何构建 JavaScript 字典和列表以选择单个栅格波段。如何可视化多波段和单波段栅格的不同组合。 2、背景 在您探索如何将 Google 地球引擎和遥感数据集成到您的研究中时&…

测试员如何快速熟悉新业务?

身处职场&#xff0c;学习新业务在所难免&#xff0c;尤其是测试人员&#xff0c;具备良好的业务知识是我们做好质量保障的前提&#xff0c;不管是职场「新人」还是「老人」&#xff0c;快速熟悉业务的能力都是不可或缺的&#xff0c;这是我们安身立命的根本。 但&#xff0c;…

简答-【1 绪论】

关键字&#xff1a; 数据类型、数据结构定义、递归关键、线性结构、非线性结构、算法特性、算法目标、时间复杂度排序

jQuery案例专题

jQuery案例专题 本学期主要担任的课程是js和jQuery&#xff0c;感觉用到的有一些案例挺有意思的&#xff0c;就对其进行了一下整理。 目录&#xff1a; 电影院的幕帘特效 手风琴特效 星光闪烁 网页轮播图 1.电影院的幕帘特效代码如下 html <!DOCTYPE html > <html…

spring面试题笔记

SpringBoot 有几种读取配置文件的方式 1.value 必须是bean里才能生效&#xff0c;&#xff0c;final或static无法生效 2ConfigurationProperties注解 ConfigurationProperties是springboot提供读取配置文件的一个注解 注意&#xff1a; 前缀定义了哪些外部属性将绑定到类的字…

分布式服务框架设计

目录 服务框架的设计 服务框架的功能 服务框架的性能指标 服务治理需要哪些功能 服务框架的设计 尽管不同的分布式服务框架实现细节存在差异&#xff0c;但是核心功能差异不大&#xff0c;下面的架构图描绘了一个分布式服务框架的整体逻辑架构 总共分为 3 层&#xff1a;1…