Spring AOP 简介

一、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.hqwc.cn/news/161606.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何快速导出、备份微信通讯录好友联系人微信号

6-9 如果因工作需要&#xff0c;你有多个微信&#xff0c;并且你的业务开发的客户都在这些微信里&#xff0c;将会面临一个问题&#xff0c;那就是备份问题&#xff0c;因为通过微信做业务&#xff0c;如果遇到微信不小心被封号&#xff0c;或者离职的交接等情况&#xff0c;客…

pg14-sql基础(三)-分组

分组 SELECT hire_date, COUNT(*) FROM employees GROUP BY hire_date;SELECT extract(year from hire_date), COUNT(*) FROM employees GROUP BY extract(year from hire_date); -- GROUP BY 1;SELECT extract(year from hire_date), department_id, COUNT(*) FROM employees…

逆向学习记录(3)工具介绍jadx、gda和jeb

1、jadx 下载地址如下&#xff0c;目前最新版本为v1.4.7&#xff0c;改成想要下载的版本号就能下载对应的版本。 https://github.com/skylot/jadx/releases/tag/v1.4.7 下载后解压&#xff0c;进入对应路径的bin文件夹内&#xff0c;运行jadx-gui.bat。 2、gda 下载地址和gi…

抵押贷款巨头 Mr. Cooper 遭受网络攻击,影响 IT 系统

导语 近日&#xff0c;美国抵押贷款巨头 Mr. Cooper 遭受了一次网络攻击&#xff0c;导致该公司的 IT 系统受到影响。这一事件引起了广泛的关注&#xff0c;使得 Mr. Cooper 的在线支付平台无法正常运行。本文将为大家详细介绍这次网络攻击事件的具体情况及其对用户和公司造成的…

Redis02-持久化策略

目录 RDB&#xff08;Redis DataBase Backup file&#xff09; RDB执行原理 AOF&#xff08;Append-Only File&#xff09; RDB和AOF对比 Redis支持多种持久化方式&#xff0c;以确保数据在内存中持久存储&#xff0c;以便在Redis服务器重启时数据不会丢失。Redis中持久化的…

1.计算机系统概述

目录 一. 计算机的发展 二. 计算机硬件的基本组成 三. 各个硬件的工作原理 &#xff08;1&#xff09;主存储器 &#xff08;2&#xff09;运算器 &#xff08;3&#xff09;控制器 &#xff08;4&#xff09;一个例子 四. 计算机系统的层次结构 五. 计算机的性能指标…

linux下使用vscode对C++项目进行编译

项目的目录结构 头文件swap.h 在自定义的头文件中写函数的声明。 // 函数的声明 void swap(int a,int b);swap.cpp 导入函数的声明&#xff0c;写函数的定义 #include "swap.h" // 双引号表示自定义的头文件 #include <iostream> using namespace std;// 函…

Idea 对容器中的 Java 程序断点远程调试

第一种&#xff1a;简单粗暴型 直接在java程序中添加log.info()&#xff0c;根据需要打印信息然后打包覆盖&#xff0c;根据日志查看相关信息 第二种&#xff1a;远程调试 在IDEA右上角点击编辑配置设置相关参数在Dockerfile中加入 "-jar", "-agentlib:jdwp…

React 项目结构小结

React 项目结构小结 简单的记录一下目前 React 项目用的依赖和实现 摸索了大半年了大概构建一套用起来还算轻松的体系……&#xff1f;基本上应该是说可以应对大部分的项目了 使用的依赖 目前项目还在 refactoring 的阶段&#xff0c;所以乱得很&#xff0c;这里是新建一个…

NLP之Bert多分类实现案例(数据获取与处理)

文章目录 1. 代码解读1.1 代码展示1.2 流程介绍1.3 debug的方式逐行介绍 3. 知识点 1. 代码解读 1.1 代码展示 import json import numpy as np from tqdm import tqdmbert_model "bert-base-chinese"from transformers import AutoTokenizertokenizer AutoToken…

基于变色龙算法的无人机航迹规划-附代码

基于变色龙算法的无人机航迹规划 文章目录 基于变色龙算法的无人机航迹规划1.变色龙搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用变色龙算法来优化无人机航迹规划。 1.变色龙…

系列十二、过滤器 vs 拦截器

一、过滤器 vs 拦截器 1.1、区别 &#xff08;1&#xff09;触发时机不一样&#xff0c;过滤器是在请求进入容器后Servlet之前进行预处理的&#xff0c;请求结束返回也是&#xff0c;是在Servlet处理完后&#xff0c;返回给前端之前&#xff1b; &#xff08;2&#xff09;过滤…