Spring的另一大的特征:AOP

目录

  • AOP (Aspect Oriented Programming)
  • AOP 入门案例(注解版)
  • AOP 工作流程——代理
  • AOP切入点表达式
  • AOP 通知类型
  • AOP通知获取数据
    • 获取切入点方法的参数
    • 获取切入点方法返回值
    • 获取切入点方法运行异常信息
  • 百度网盘分享链接输入密码数据错误兼容性处理

AOP (Aspect Oriented Programming)

  • AOP (Aspect Oriented Programming) 面向切面编程 ,指导开发者如何组织程序结构

OOP (Object Oriented Programming) 面向对象编程

  • AOP 的作用: 在不惊动原始设计的基础上为其进行功能增强
  • Spring 理念: 无入侵式/无侵入式

在这里插入图片描述

  • 连接点(JointPoint): 程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。

    • 在 SpringAOP 中,理解为方法的执行
  • 切入点(Pointcut): 匹配连接点的式子

    • 在 SpringAOP 中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
      • 一个具体方法:eg : com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:eg : 所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知(Advice): 在切入点处执行的操作,也就是共性功能

    • 在 SpringAOP 中,功能最终以方法的形式呈现
  • 通知类: 定义通知的类

  • 切面(Aspect): 描述通知与切入点的对应关系

AOP 入门案例(注解版)

- 导入 aop 相关坐标
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>

spring-context 坐标依赖 spring-aop 坐标
在这里插入图片描述

    • 定义dao 接口与实现类
public interface BookDao {
    public void save();

    public void update();

    public void delete();

    public void select();
}

@Repository
public class BookDaoImpl implements BookDao {

    public void save() {
        //记录程序当前执行执行(开始时间)
        Long startTime = System.currentTimeMillis();
        //业务执行万次
        for (int i = 0;i<10000;i++) {
            System.out.println("book dao save ...");
        }
        //记录程序当前执行时间(结束时间)
        Long endTime = System.currentTimeMillis();
        //计算时间差
        Long totalTime = endTime-startTime;
        //输出信息
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
    }

    public void update(){
        System.out.println("book dao update ...");
    }

    public void delete(){
        System.out.println("book dao delete ...");
    }

    public void select(){
        System.out.println("book dao select ...");
    }
}

    • 定义通知类,制作通知
    • 定义切入点:切入点定义依托一个不具有实际意义的方法进行,即无参数,无返回值,方法体无实际逻辑
    • 绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置
    • 定义通知类受Spring容器管理,并定义当前类为切面类
@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(* com.itheima.dao.BookDao.*d*(..))")
    private void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("------------------------------");
        Long startTime = System.currentTimeMillis();
        for (int i = 0 ; i<10000 ; i++) {
            //调用原始操作
            pjp.proceed();
        }
        Long endTime = System.currentTimeMillis();
        Long totalTime = endTime-startTime;
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
        return null;
    }

}
    • 开启 Spring 对 AOP 注解驱动支持 : @EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}

AOP 工作流程——代理

  1. Spring 容器启动
  2. 读取所有切面配置中的切入点
  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
    • 匹配失败,创建对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取bean执行方法
    • 获取bean,调用方法并执行,完成操作
    • 获取bean是代理对象时, 根据代理对象的运行模式运行原始方法与增强的内容,完成操作
  • 目标对象(Target) : 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的。
  • 代理(Proxy) : 目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

AOP切入点表达式

  • 切入点:要进行增强的方法
  • 切入点表达式:要进行增强的方法的描述方式

在这里插入图片描述

  • 切入点表达式标准格式: 动作关键字 (访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
execution (public User com.itheima.service.UserService.findById (int))
    • 动作关键字: 描述切入点的行为动作,例如execution表示执行到指定切入点
    • 访问修饰符: public , private 等 可省略
    • 返回值
    • 包名
    • 类/接口名
    • 方法名
    • 参数
    • 异常名:方法定义中抛出指定异常,可省略
  • 可以使用通配符描述切入点,快速描述:

    • eg: * : 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
execution (public * com.itheima.*.UserService.find* (*))

匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

    • eg: . . :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
execution (public User com..UserService.findById (..))

匹配com包下的任意包中的UserService类或接口中所有名称为findByld的方法

    • eg: + :专用于匹配子类类型
execution (* *..*Service+.*(..))

AOP 通知类型

  • AOP 通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
  • 5 种类型
    • 前置通知
    • 后置通知
    • 环绕通知 (重点) :通过ProceedingJoinPoint 对原始方法调用,获得返回值,最终返回这个返回值
    • 返回后通知 (了解)
    • 抛出异常后通知 (了解)
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}

@Pointcut("execution(int com.itheima.dao.BookDao.select())")
    private void pt2(){}

    //@Before:前置通知,在原始方法运行之前执行
//    @Before("pt()")
    public void before() {
        System.out.println("before advice ...");
    }

    //@After:后置通知,在原始方法运行之后执行
//    @After("pt2()")
    public void after() {
        System.out.println("after advice ...");
    }

    //@Around:环绕通知,在原始方法运行的前后执行
//    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Object ret = pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }

//    @Around("pt2()")
    public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Integer ret = (Integer) pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }

    //@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
//    @AfterReturning("pt2()")
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }

    //@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行
    @AfterThrowing("pt2()")
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
}
  • @Around 注意事项
    • 环绕通知必须依赖形参 ProceedingJoinPoint 才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    • 通知中如果未使用 ProceedingJoinPoint 对原始方法进行调用将跳过原始方法的执行
    • 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
    • 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
    • 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

AOP通知获取数据

获取切入点方法的参数

  • JoinPoint: 适用于前置、后置、返回后、抛出异常后通知
  • JoinPoint 对象描述了连接点方法的运行状态,可以获取到原始方法的调用参数
	@Before("pt()")
    public void before(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }
  • ProceedJoinPoint: 适用于环绕通知, 是 JoinPoint 的子类
	@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        Object[] args = pjp.getArgs();
        System.out.println(Arrays.toString(args));
        ret = pjp.proceed(args);
        return ret;
    }

获取切入点方法返回值

  • 返回后通知
    //设置返回后通知获取原始方法的返回值,要求returning属性值必须与方法形参名相同
    @AfterReturning(value = "pt()",returning = "ret")
    public void afterReturning(JoinPoint jp, String ret) {
        System.out.println("afterReturning advice ..."+ret);
    }
  • 环绕通知 可以手工书写对原始方法的调用,得到的结果即为原始方法的返回值。
	@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        ret = pjp.proceed(args);
        return ret;
    }

获取切入点方法运行异常信息

  • 抛出异常后通知:可以获取切入点方法中出现的异常信息,使用形参可以接收对应的异常对象
    //设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同
    @AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println("afterThrowing advice ..."+t);
    }
  • 环绕通知
	@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) {
        Object ret = null;
        try {
            ret = pjp.proceed(args);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return ret;
    }

百度网盘分享链接输入密码数据错误兼容性处理

@Around("DataAdvice.servicePt()")
public Object trimString(ProceedingJoinPoint pjp) throws Throwable {
	Object[] args = pjp.getArgs();
	//对原始参数中的每一个参数进行操作
	for (int i = 0; i < args.length; i++) {
		if (args[i].getClass().equals(String.class)) {
			args[i] = args[i].toString().trim();
		}
	}
	return pjp.proceed(args);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux基础】Linux自动化构建工具make/makefile

背景 会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件需要后…

性格正直的人适合什么职业?

有信仰&#xff0c;有责任&#xff0c;有骨气&#xff0c;有尊严&#xff0c;这应该是大多数人对正直的人的理解&#xff0c;他们的心中有信仰&#xff0c;肩上有责任&#xff0c;灵魂有骨气&#xff0c;头上有尊严&#xff0c;不管在什么时候都能够坚守道德准则&#xff0c;不…

【文生视频】Diffusion Transformer:OpenAI Sora 原理、Stable Diffusion 3 同源技术

文生视频 Diffusion Transformer&#xff1a;Sora 核心架构、Stable Diffusion 3 同源技术 提出背景变换器的引入Diffusion Transformer (DiT)架构Diffusion Transformer (DiT)总结 OpenAI Sora 设计思路阶段1: 数据准备和预处理阶段2: 架构设计阶段3: 输入数据的结构化阶段4: …

蓝桥杯算法赛 第 6 场 小白入门赛 解题报告 | 珂学家 | 简单场 + 元宵节日快乐

前言 整体评价 因为适逢元宵节&#xff0c;所以这场以娱乐为主。 A. 元宵节快乐 题型: 签到 节日快乐&#xff0c;出题人也说出来自己的心愿, 祝大家AK快乐! import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.println(&qu…

信息抽取(UIE):使用自然语言处理技术提升证券投资决策效率

一、引言 在当今快速变化的证券市场中&#xff0c;信息的价值不言而喻。作为一名资深项目经理&#xff0c;我曾领导一个关键项目&#xff0c;旨在通过先进的信息抽取技术&#xff0c;从海量的文本数据中提取关键事件&#xff0c;如企业并购、新产品发布以及政策环境的变动。这些…

学会字符转换

字符转换 题目描述&#xff1a;解法思路&#xff1a;解法代码&#xff1a;运行结果&#xff1a; 题目描述&#xff1a; 输入⼀一个字符串&#xff0c;将字符串中大写字母全部转为小写字母&#xff0c;小写字母转成大写字母&#xff0c;其他字符保持不变。注&#xff1a;字符串…

typescript使用解构传参

看下面这个函数 interface Student {id: number;name: string;class: string;sex: string;}function matriculation(student: Student) {//...}我们要调用它,就需要传递一个实现了Student约束的对象进去 interface Student {id: number;name: string;class: string;sex: string…

音视频数字化(数字与模拟-电视)

上一篇文章【音视频数字化(数字与模拟-音频广播)】谈了音频的广播,这次我们聊电视系统,这是音频+视频的采集、传输、接收系统,相对比较复杂。 音频系统的广播是将声音转为电信号,再调制后发射出去,利用“共振”原理,收音机接收后解调,将音频信号还原再推动扬声器,我…

Liunx--nginx负载均衡--前后端分离项目部署

一.nginx简介 Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;它以其轻量级、占用资源少、并发能力强而广受欢迎。 详细介绍 开发背景与特点&#xff1a;Nginx由俄罗斯人Igor Sysoev开发&#xff0c;它是一个自由的、开源的软件。Nginx设计上注重性能和效率&#xff0c;能…

数据库安全性与完整性设计

文章标签集合[数据库安全,数据敏感,通信安全,MD5,盐加密] 1 系统设计 1.1设计目标 &#xff08;1&#xff09;确定系统中需要保护的敏感数据和通信内容&#xff1b; &#xff08;2&#xff09;设计合适的签名、加密和解密算法&#xff1b; &#xff08;3&#xff09;实现…

docker-compose 搭建laravel环境

laravel环境包含nginx,mysql,php7.4,redis 一、安装好docker后pull镜像 1.nginx镜像 docker pull nginx:latest单独启动容器 docker run --name nginx -p 80:80 -d nginx 2.php镜像 docker pull php:7.4-fpm3.mysql镜像 docker pull mysql:5.74.redis镜像 docker pull r…

Mysql5.7主从复制搭建

注意不适用Mysql8 Docker搭建Mysql主从复制 docker run -p 3307:3306 --name mysql-master \ -v /usr/local/develop/mysql-master/log:/var/log/mysql \ -v /usr/local/develop/mysql-master/data:/var/lib/mysql \ -v /usr/local/develop/mysql-master/conf:/etc/mysql/con…

基于相位的运动放大:如何检测和放大难以察觉的运动(02/2)

目录 一、说明二、算法三、准备处理四、高斯核五、带通滤波器六、复杂的可操纵金字塔七、最终预处理步骤八、执行处理九、金字塔的倒塌十、可视化结果十一、结论 一、说明 日常物体会产生人眼无法察觉的微妙运动。在视频中&#xff0c;这些运动的幅度小于一个像素&#xff0c;…

记录一些mac电脑重装mysql和pgsql的坑

为什么要重装,是想在mac电脑 创建data目录…同事误操作,导致电脑重启不了.然后重装系统后,.就连不上数据库了.mysql和pgsql两个都连不上.网上也查了很多资料.实在不行,.就重装了… 重装mysql. 1.官网下载 https://www.mysql.com/downloads/ 滑到最下面 选择 选择对应的芯片版本…

密码学及其应用(应用篇15)——0/1背包问题

1 问题背景 背包问题是一个经典的优化问题&#xff0c;在计算机科学和运筹学中有着广泛的应用。具体到你提到的这个问题&#xff0c;它是背包问题中的一个特例&#xff0c;通常被称为0/1背包问题。这里&#xff0c;我们有一系列的正整数 &#xff0c;以及一个正整数&#xff0c…

【Linux】--- 详解Linux软件包管理器yum和编辑器vim

目录 一、Linux软件包管理器 - yum1.1 yum和软件包是什么1.2 Linux系统(Centos)的生态1.3 yum相关操作1.4 yum本地配置 二、Linux编辑器 - vim使用2.1 vim的基本概念2.2 vim命令模式命令集2.3 vim末行模式命令集2.4 关于vim的几个相关问题 一、Linux软件包管理器 - yum 1.1 yu…

Open3D 点云法向量计算与可视化 (25)

Open3D 点云法向量计算与可视化 (25) 一、算法原理二、算法实现三、可视化显示和长度调节一、算法原理 通常计算点云的法向量可以使用以下两种常见的方法: 最小二乘法(Least Squares Method):该方法通过拟合局部表面的平面来计算法向量。对于给定点周围的邻域,可以通过…

云尚办公-0.3.0

5. controller层 import pers.beiluo.yunshangoffice.model.system.SysRole; import pers.beiluo.yunshangoffice.service.SysRoleService;import java.util.List;//RestController&#xff1a;1.该类是控制器&#xff1b;2.方法返回值会被写进响应报文的报文体&#xff0c;而…

分布式架构(分布式ID+分布式事务)

分布式架构 分布式事务产生的场景&#xff1a; 跨JVM进程产生的分布式事务 单体系统访问多个数据库实例 多服务访问同一个数据库实例 CAP理论 C&#xff1a;一致性&#xff0c;指写操作后的读操作可以读取到最新的数据状态&#xff0c;当数据分布在多个节点上&#xff0…

【C++】C++对C语言的关系,拓展及命名空间的使用

文章目录 &#x1f4dd;C简述C融合了3种不同的编程方式&#xff1a;C和C语言关系是啥呢&#xff1f;C标准 &#x1f320;C应用&#x1f320;C语言优点第一个C程序 &#x1f320;命名空间&#x1f320;命名空间的使用命名空间的定义 &#x1f320;怎么使用命名空间中的内容呢&am…