2023.12.2 关于 Spring AOP 详解

目录

Spring AOP

Spring AOP  常见使用场景

 AOP 组成

切面(类)

切点(方法)

通知

​编辑

前置通知(@Before)

后置通知(@After)

返回通知(@AfterReturning)

异常通知(@AfterThrowing)

环绕通知(@Around)

连接点

Spring AOP 实现  

 切点表达式说明

 Spring AOP 实现原理

织入

动态代理

JDK 动态代理

CGLIB


Spring AOP

  • AOP (Aspect Oriented Programming)译为 面向切面编程
  • AOP 为一种思想,是对某一类事情的集中处理
  • Spring AOP 是一个框架,提供了对 AOP 思想的实现
  • Spring AOP 是 Spring 的三大核心思想之一,另外两个是 IOC(控制反转)和 DI(依赖注入)

实例理解

  • 在我们程序中,经常存在一些系统性的需求
  • 这些需求代码会散落穿插在各个业务逻辑中,非常冗余且不利于维护,具有极高的耦合性
  • AOP 的目的就是将这些非业务代码完全提取出来,与业务代码分离,并寻找节点切入业务代码中

Spring AOP  常见使用场景

  • 统一登录检测机制
  • 统一方法的执行时间统计
  • 统一的返回格式设置
  • 统一异常处理
  • 事务的开始和提交

实例理解

  • 假设我们有一个 Web 应用其中有很多需要用户登录后才能访问的页面
  • 为了避免在每个需要登录的方法中都检查用户是否已经登录
  • 我们便可以使用 Spring AOP 来解决该问题

 AOP 组成

切面(类)

  • 在程序中就是对某一功能进行统一处理的类
  • 这个类包含了很多方法,这些方法就是由 切点 和 通知 组成

切点(方法)

  • 定义一个进行主动拦截的规则
  • 所谓的拦截就是 对用户向服务器发送的请求进行拦截,检测用户的操作是否符合预期,发现问题并统一处理的过程

通知

  • 通知就是 AOP 的具体执行动作
  • 在程序中被拦截后会触发一个具体的动作,即通知中具体实现的业务代码

  • 在 Spring 中可以在方法上使用以下注解,设置方法为通知方法,在满足条件后会通知本方法进行调用

前置通知(@Before)

  • 执行目标方法(实际要执行的方法)之前执行的方法

后置通知(@After)

  • 执行了目标方法之后执行的方法

返回通知(@AfterReturning)

  • 目标方法返回(return)的时候,执行的方法

异常通知(@AfterThrowing)

  • 在执行目标方法抛出异常时,执行的方法
  • 通常结合事务一起使用,如果未抛出异常则提交成功,如果抛出异常则回滚事务

环绕通知(@Around)

  • 在目标方法调用前、后都执行的通知
  • 如果已经有了前置和后置通知,再使用环绕通知,那么周期范围就在前置通知之前,后置通知之后
  • 通常可用于计算目标方法执行的时间


连接点

  • 所有可能触发切点的点就叫做连接点

Spring AOP 实现  

  • 此处我们想实现拦截 UserController 类中的所有方法

添加 Spring Boot AOP 依赖

  • 创建 Spring Boot 项目时,无法选择添加 Spring boot AOP 依赖
  • 所以我们可以选择进入 中央仓库 来选择与当前 Spring Boot 版本相对应的 AOP

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

定义切面(类)

  • 使用 @Aspect 注解修饰该类,告诉 Spring Boot 该类为一个切面类
package com.example.demo.component;import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Aspect // 切面
@Component // 不能省略
public class UserAspect {
}

定义切点(方法)

  • 定义拦截规则,实现拦截 UserController 类中的所有方法
  • 使用 @Pointcut 修饰一个方法,该方法无需有方法体
  • 方法名就是起到一个标识的作用,标识通知方法具体指的是哪一个切点,因为切点可能有很多个
package com.example.demo.component;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect // 切面
@Component // 不能省略
public class UserAspect {//    切点(配置拦截规则)@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointcut() {}
}

创建通知

  • 此处我们创建三个通知
  • 前置通知、后置通知、环绕通知
package com.example.demo.component;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Aspect // 切面
@Component // 不能省略
public class UserAspect {//    切点(配置拦截规则)@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")public void pointcut() {}/** 前置通知* */@Before("pointcut()")public void beforeAdvice() {System.out.println("执行了前置方法");}/** 后置通知* */@After("pointcut()")public void afterAdvice() {System.out.println("执行了后置方法");}/** 环绕通知* 此处的 joinPoint 就是连接点,即方法本身* */@Around("pointcut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {Object obj = null;System.out.println("进入了环绕通知");obj = joinPoint.proceed();System.out.println("退出了环绕通知");
//        最后将执行的结果交给框架return obj;}
}

创建连接点

  • 此处我们对照 切点的拦截规则
  • 创建一个 UserController 类
  • 并在该类中创建两个连接点
  • 当我们在浏览器中访问这两个连接点时,会触发切点的拦截规则,对其进行拦截,然后执行各种通知
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {@RequestMapping("/user/sayhi")public String sayHi() {System.out.println("执行了 sayHi 方法");return "hi spring boot aop";}@RequestMapping("/user/login")public String login() {System.out.println("执行了 login 方法");return "do user login";}
}

执行结果

  • 运行 Spring Boot 项目
  • 此处我们在浏览器中输入对应的 URL 地址,访问 UserController 中的 sayHi 方法


图示理解

 切点表达式说明

  • 该切点表达式属于 AspectJ 的语法
  • execution( <修饰符> <返回类型> <包.类.方法(参数)> <异常> )


实例理解

 Spring AOP 实现原理

  • Spring 的切面是代理类实现的
  • 代理类包裹了 目标对象
  • 即 用户只能先通过代理类,进行校验,如果没有问题才会进一步访问到目标对象

织入

  • 指代理生成的时机
  • 一般情况下,Spring AOP 动态代理的植入时机是程序的运行期

动态代理

  • Spring AOP 是构建在动态代理基础上的,所以 Spring 对 AOP 的支持局限于方法级别的拦截
  • Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理

JDK 动态代理

  • 基于接口实现
  • 底层通过反射实现
  • 要求代理类一定要实现接口

CGLIB

  • 基于类的子类实现
  • 底层通过字节码增强技术生成子类实现
  • 不能代理被 final 修饰的类,因为其无法生成子类

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

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

相关文章

龙芯loongarch64服务器编译安装maturin

前言 maturin 是一个构建和发布基于 Rust 的 Python 包的工具,但是在安装maturin的时候,会出现如下报错:error: cant find Rust compiler 这里记录问题解决过程中遇到的问题: 1、根据错误的提示需要安装Rust Compiler,首先去其官网按照官网给的解决办法提供进行安装 curl…

loguru的简单使用

详细使用&#xff1a;Table of contents — loguru documentation 【1】日志的级别 日志级别默认分为6种 1、NOTSET (0)2、DEBUG (1)3、INFO (2)4、WARNING (3)5、ERROR (4)6、CRITICAL (5) logging 执行时输出大于等于设置的日志级别的日志信息&#xff0c;如设置日…

阿里系列-淘宝接口抓取及相关问题

阿里系-淘宝接口抓取 一、安装charlse抓包工具 官方下载地址 安装证书 二、安装xposed hook框架 Xponsed简介 具体安装步骤 三、安装模块 关闭阿里系ssl验证 开启http模式 支持支付宝、淘宝、淘宝直播各个接口抓取 四、效果如下 接下去一段时间更新阿里系相关接口 文章目录 一、…

SmartSoftHelp8,代码版权保护

1.Html网页前端添加作者开发信息 2. Html网页添加版权信息 3. Css添加作者开发信息 4. JavaScript添加作者开发信息 5. C井后端代码添加作者开发信息 6. Dll内裤添加作者开发信息 7.应用程序添加开发作者信息&#xff0c;著作权&#xff0c;应用版权信息 下载地址&#…

函数柯里化

前端面试大全JavaScript函数柯里化 &#x1f31f;经典真题 &#x1f31f;什么是函数柯里化 &#x1f31f;柯里化快速入门 &#x1f31f;函数柯里化实际应用 &#x1f31f;封装通用柯里化函数 &#x1f31f;一道经典的柯里化面试题 &#x1f31f;真题详解 &#x1f31f;…

C语言结构体详解(二)(能看懂文字就能明白系列)文章很长,慢慢品尝

系列文章目录 第一章 结构体的介绍和基本使用 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言前面一篇文章主要介绍了结构体的基础…

C语言-结构体

---------------------------- ------------------ 岁月漫长心怀热爱&#xff0c;携手共赴星辰大海 --------今天来到我们自定义类型 -----结构体的讲解 目录 结构体的类型声明和初始化 结构体的类型声明 结构体成员的直接访问 结构体成员的间接访问 嵌套结构体进行访问 使用…

基于搜索协议实现工业设备升级

目录 1、背景引入 2、技术分析 3、过程概述 4、服务器端流程 5、客户端流程 6、效果展示 7、源码 7.1 master&#xff08;主控&#xff09; 7.2 device&#xff08;设备&#xff09; 8、注意事项 1、背景引入 在工业生产中&#xff0c;设备的升级和维护是非常重要的…

一起学docker系列之十六使用Docker Compose简化容器编排

目录 1 前言2 Docker Compose是什么&#xff1f;3 Docker Compose安装步骤3.1 **下载Compose**3.2 **设置权限**3.3 **创建符号链接&#xff08;可选但建议以便使用&#xff09;** 4 Docker Compose的核心概念4.1 **YAML文件&#xff08;docker-compose.yml&#xff09;**4.2 *…

SpringBootCache缓存——j2cache

文章目录 缓存供应商变更&#xff1a;j2cache 缓存供应商变更&#xff1a;j2cache <!-- https://mvnrepository.com/artifact/net.oschina.j2cache/j2cache-core --><dependency><groupId>net.oschina.j2cache</groupId><artifactId>j2cache-cor…

【数据挖掘】国科大刘莹老师数据挖掘课程作业 —— 第三次作业

Written Part 1. 基于表 1 1 1 回答下列问题&#xff08;min_sup40%, min_conf75%&#xff09;&#xff1a; Transaction IDItems Bought0001{a, d, e}0024{a, b, c, e}0012{a, b, d, e}0031{a, c, d, e}0015{b, c, e}0022{b, d, e}0029{c, d}0040{a, b, c}0033{a, d, e}0038…

[原创]C++98升级到C++20的复习旅途-从汇编及逆向角度去分析“constexpr“关键字

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XXQQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi…

机器视觉最全面试题总结

文章目录 1. 为什么需要做特征归一化、标准化&#xff1f;2. 常用常用的归一化和标准化的方法有哪些&#xff1f;3. 介绍一下空洞卷积的原理和作用4. 怎么判断模型是否过拟合&#xff0c;有哪些防止过拟合的策略&#xff1f;5. 除了SGD和Adam之外&#xff0c;你还知道哪些优化算…

uniapp 使用安卓模拟器运行

uniapp 启动方式有很多种,这里介绍使用模拟器启动uniapp 要使用模拟器启动uniapp肯定少不了安装模拟器(废话) 这里选着浏览器推荐的第一个模拟器mumu模拟器 下载好了mumu安装包后就是安装了,这个过于小白,就不介绍了 2. 查看模拟器的adb端口号, mumu的adb查看端口号与众不同…

6-48.日期类的设计与实现

使用重载运算符&#xff08;&#xff0c;&#xff0c;<<等&#xff09;实现日期类的操作。功能包括&#xff1a; 1&#xff09;设置日期&#xff0c;如果日期设置不符合实际&#xff0c;则设置为默认日期&#xff08;1900年1月1日&#xff09; 2&#xff09;在日期对象中…

Java 表达式引擎

企业的需求往往是多样化且复杂的&#xff0c;对接不同企业时会有不同的定制化的业务模型和流程。我们在业务系统中使用表达式引擎&#xff0c;集中配置管理业务规则&#xff0c;并实现实时决策和计算&#xff0c;可以提高系统的灵活性和响应能力。 引入规则引擎似乎就能解决这个…

数据结构:堆的实现思路

我们之前写过堆的实现代码&#xff1a;数据结构&#xff1a;堆的实现-CSDN博客 这篇文章我们了解一下堆到底是如何实现的 1.堆向下调整算法 现在我们给出一个数组&#xff0c;逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆 向下调…

栈的链式存储(详解)

栈的链式存储 栈的链式存储是通过链表来实现的&#xff0c;每个节点包含一个元素和一个指向下一个节点的指针。链式存储的栈不需要提前分配内存空间&#xff0c;可以动态地增加或减少元素。 在链式存储中&#xff0c;栈顶元素通常是链表的头节点&#xff0c;栈底元素是链表的…

高光谱遥感影像分类项目开源

热烈欢迎大家在git上star&#xff01;&#xff01;&#xff01;冲鸭&#xff01;&#xff01;&#xff01; 我研究生期间主要是做高光谱遥感影像分类的&#xff0c;毕业论文也是基于深度学习的高光谱遥感影像分类课题&#xff0c;转眼间已经毕业四年了&#xff0c;如今把这块材…

每天一点python——day84

#每天一点Python——84 #异常处理机制try—except—else #异常处理机制try—except—else如果try块中没有抛出异常&#xff0c;则执行else块&#xff0c;如果try中抛出异常&#xff0c;则执行except块#示例&#xff1a; try:a int(input(请输入第一个整数&#xff1a;))b in…