7、Spring_AOP

一、Spring AOP 简介

1.概述

  • 对于spring来说,有三大组件,IOC,ID,AOP

  • aop概述:AOP(Aspect Oriented Programming)面向切面编程。

  • 作用:不改变原有代码设计的基础上实现功能增强

    • 例子

      • 传统打印日志

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVTRWA8Z-1692777970686)(picture/image-20221103171648609.png)]

      • 使用AOP增强之后

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scLGJ5cf-1692777970687)(picture/image-20221103171749982.png)]

2.代理模式

  • 如果没有听过代理模式,点击链接先学习代理模式 : https://www.bilibili.com/video/BV1tY411Z799/?share_source=copy_web&vd_source=fdccda7d1272a2e0f49cadca354a5073
  • 静态代理
  • 动态代理
    • jdk 动态代理
    • cglib 动态代理

二、AOP概念

1.案例分析

  • 创建类提供增删改查方法,实现事务增强操作功能

    public interface IStudentService {void save(Student student);int update(Student student);Student queryStudentById(Long id);
    }
    
  • 接口实现类

    public class StudentServiceImpl implements IStudentService {public void save(Student student) {
    //        System.out.println("开启事务");System.out.println("保存操作");
    //        System.out.println("关闭事务");}public int update(Student student) {
    //        System.out.println("开启事务");System.out.println("更新操作");
    //        System.out.println("关闭事务");return 0;}public Student queryStudentById(Long id) {System.out.println("查询操作");return null;}
    }
    
  • 提供通知类

    public class TransactionAdvice {public void before(){System.out.println("开启事务");}public void after(){System.out.println("关闭事务");}public void invoke(){before();//具体的业务执行after();}
    }
    

2.核心概念

2.1概念

  • 连接点(JoinPoint):对于需要增强的方法就是连接点
  • 切入点(Pointcut):需要增强的方法是切入点,匹配连接点的式子
  • 通知(Advice):存放需要增强功能的共性代码,就叫通知
  • 切面(Aspect):通知是需要增强的功能存在多个,切入点是需要增强的方法也存在多个,需要去给切入点和通知做关联,知道哪个切入点对应哪个通知,这种描述关系就叫切面
  • 通知类:存放通知(方法)的类

2.2图示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1PL1Rii-1692777970688)(picture/image-20221103181229013.png)]

3.核心概念

  • 目标对象 target
  • 代理 proxy

三、通过注解实现AOP配置

1.导入依赖

  • 导入aop依赖

    <dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version>
    </dependency>
    
  • 导入Spring依赖

    <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version>
    </dependency>
    

2.配置AOP支持

  • @EnableAspectJAutoProxy

  • 说明

    名称@EnableAspectJAutoProxy
    使用位置配置类上
    作用开启注解的aop支持
  • 代码

    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan("cn.sycoder")
    public class AppConfig {
    }
    

3.创建切面类

  • @Aspect

  • 说明

    名称@Aspect
    作用设置当前类为切面类
    使用位置类上
    属性String value() default “”;可以给切面指定名称
  • @Pointcut

  • 说明

    名称@Pointcut
    作用设置切入点方法
    使用位置方法上
    属性String value() default “”;切入点表达式
  • 代码

    @Component
    @Aspect
    public class TransactionAdvice {//定义通知 绑定切点和通知的关系@Before("pc()")public void before(){System.out.println("开启事务");}@After("pc()")public void after(){System.out.println("关闭事务");}//定义切点@Pointcut("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){}
    }
    

4.测试aop

  • 测试代码

    @Testpublic void testAop(){AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);IStudentService bean = applicationContext.getBean(IStudentService.class);bean.save(null);}
    
    • 打印输出

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9xF3fAI-1692777970689)(picture/image-20221103205153372.png)]

5.各种通知

5.1@Before

  • 前置通知:被代理的目标方法执行前执行

  • 说明

    名称@Before
    使用位置方法上
    作用前置通知,目标方法执行前执行
    属性String value(); 切入点表达式
    可以提供的入参JoinPoint joinPoint ,切点
  • 使用

    @Before("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")
    public void before(JoinPoint joinPoint){System.out.println("开启事务");
    }
    

5.2@After

  • 后置通知:被代理的目标方法执行后执行

  • 说明

    名称@After
    使用位置方法上
    作用后置通知:被代理的目标方法执行后执行
    属性String value(); 切入点表达式
    可以提供的入参JoinPoint joinPoint ,切点
  • 使用

    @After("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")
    public void after(){System.out.println("关闭事务");
    }
    

5.3@AfterReturning

  • 返回通知:被代理的目标方法成功结束后执行

  • 说明

    名称@AfterReturning
    使用位置方法上
    作用返回通知:被代理的目标方法成功结束后执行
    属性String value(); 切入点表达式,String returning();方法返回值
    可以提供的入参JoinPoint joinPoint ,切点,方法返回值 obj
  • 使用

    • 如果想要得到返回值,需要在注解上添加参数returning名称,对应方法参数名称
    • 切面表达式的返回值为*而不是void
    @AfterReturning(returning = "obj",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.update(..))")
    public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知");
    }
    

5.4@AfterThrowing

  • 异常通知:被代理的目标方法出现异常后执行

  • 说明

    名称@AfterThrowing
    使用位置方法上
    作用异常通知:被代理的目标方法出现异常后执行
    属性String value(); 切入点表达式String throwing();异常返回
    可以提供的入参JoinPoint joinPoint ,切点,异常返回值 th
  • 使用

    @AfterThrowing(throwing = "th",value = "execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")
    public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("异常通知");
    }
    

5.5@Around

  • 环绕通知:可以使用 try 代码块把被代理的目标方法围绕住,就可以做自己想做的操作,可以在里面做任何的操作

  • 说明

    名称@Around
    使用位置方法上
    作用异常通知:被代理的目标方法出现异常后执行
    属性String value(); 切入点表达式
    可以提供的入参ProceedingJoinPoint joinPoint,可以通过该对象调用原始方法
  • 使用

    @Around("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("前置通知");Object proceed = joinPoint.proceed();//执行目标方法System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) {System.out.println("异常通知");throwable.printStackTrace();} finally {}}
    

5.6各种通知执行顺序

  • 环绕通知—前置通知—目标方法—返回通知或异常通知—后置通知

6.切入点表达式

  • 概述:切入点表达式是用来寻找目标代理方法的

    execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))
    
  • 图示

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrwcESLt-1692780385498)(picture/image-20221104150052284.png)]

  • 表达式实操

    编号名称使用位置作用
    1*代替权限修饰符和返回值表示任意权限和返回
    2*使用到包位置一个*表示当前一层的任意
    3*…使用到包位置任意包任意类
    4*使用到类表示任意类
    5*Service使用到类表示寻找以Service 结尾的任意接口或类
    6使用到参数表示任意参数
    1. 案例:找到实现类中的任意save方法

      execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..))
      
    2. 案例:sycoder 包下面的类中的任意update 方法

      execution(* cn.sycoder.*.update(..))
      
    3. 案例:找到sycoder 包下面及其任意子包中的任意update 方法

      execution(* cn.sycoder.*..update(..))
      
    4. 案例:找到service 下面任意类的update 方法

      execution(* cn.sycoder.service.*.update(..))
      
    5. 案例:找到以Service 结尾的接口或者类的update 方法

      execution(* cn.sycoder.service.*Service.update(..))
      
    6. 案例:找到Service 结尾的接口或者类的update 方法,任意参数的

      execution(* cn.sycoder.service.*Service.update(..))
      
  • 注意:如果你切的越模糊,那性能就会越低,所以实际开发中,建议把范围切小一点

  • 优先级

    • 如果想手动指定优先级关系,可以使用@Order(1)注解
      • 提供的值越小,优先级越高

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdsnfMJz-1692780385499)(picture/image-20221104155839835.png)]

  • 重用切入点表达式

    • 定义切点

      @Component
      @Aspect
      public class TransactionAdvice {//定义切点@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切点");}
      }
      
    • 在其他切面类通知里面重用切点

      @Component
      @Aspect
      public class LogAdvice {@Before("cn.sycoder.advice.TransactionAdvice.pc()")public void log(){System.out.println("-0-----这里是打印日志");}
      }
      
    • 切面内部自己重用

      @Component
      @Aspect
      public class TransactionAdvice {//定义切点@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切点");}//定义通知 绑定切点和通知的关系//前置通知@Before("pc()")public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("开启事务");}
      

7.获取通知相关信息

  • 获取连接点信息,在通知方法中添加参数 JoinPoint 即可

    @Before("pc()")
    public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("开启事务");
    }
    
  • 获取目标方法返回值

    • 使用AfterReturning 中的 returning 属性,这里指定的名称即是我们方法传入的名称
    @AfterReturning(returning = "obj",value = "pc()")public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知");}
    
  • 获取异常

    • 使用AfterThrowing 中的 throwing 属性,这里指定的名称即是我们方法传入的参数名称
    @AfterThrowing(throwing = "th",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("异常通知");}
    
  • 如果使用环绕通知

    • 使用ProceedingJoinPoint joinPoint
     @Around("execution(void cn.sycoder.service.*..save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("环绕通知");
    //            System.out.println("前置通知");Object proceed = joinPoint.proceed();//执行目标方法
    //            System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) {
    //            System.out.println("异常通知");throwable.printStackTrace();} finally {}}
    

四、XML配置AOP

1.导入依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><!--            <scope>test</scope>--></dependency>

2.基本准备

  • 创建 service 接口以及方法

    public interface IStudentService {void save(Student student);
    }
    
    public class StudentServiceImpl implements IStudentService {public void save(Student student) {System.out.println("保存操作");}
    }
    
  • 创建切面类

    public class XmlAspect {public void before(){System.out.println("前置通知");}public void pointCut(){}public void after(JoinPoint joinPoint){System.out.println("后置通知");}public void afterReturning(Object obj){System.out.println("返回通知"+obj);}public void afterThrowing(Throwable t){System.out.println("异常通知");}
    }
    

3.创建xml 配置文件

  • aop.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="service" class="cn.sycoder.service.impl.StudentServiceImpl"></bean><bean id="xmlAspect" class="cn.sycoder.aspect.XmlAspect"></bean><aop:aspectj-autoproxy/><aop:config>
    <!--        配置切面类--><aop:aspect ref="xmlAspect">
    <!--            配置切点--><aop:pointcut id="pc" expression="execution(* cn.sycoder.service.*..*(..))"/>
    <!--            配置前置通知--><aop:before method="before" pointcut-ref="pc"></aop:before>
    <!--            配置后置通知--><aop:after method="after" pointcut-ref="pc"></aop:after>
    <!--            配置返回通知--><aop:after-returning method="afterReturning" returning="obj" pointcut-ref="pc"></aop:after-returning>
    <!--            异常通知--><aop:after-throwing method="afterThrowing" throwing="t" pointcut-ref="pc"></aop:after-throwing></aop:aspect></aop:config>
    </beans>
    

4.总结

  • 以后在公司使用注解的方式最流行,所以,xml 配置作为了解内容即可

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

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

相关文章

基于VHDL语言的汽车测速系统设计_kaic

摘 要 汽车是现代交通工具。车速是一项至关重要的指标。既影响着汽车运输的生产率,又关乎着汽车行驶有没有超速违章&#xff0c;还影响着汽车行驶时人们的人身安全。而伴随着我国国民的安全防范意识的逐步增强&#xff0c;人们也开始越来越关心因为汽车的超速而带来的极其严重…

day 29 柱状图

# 导入柱状图的包 from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 创建柱状图对象 bar Bar()# 添加x轴数据 bar.add_xaxis(["中国", "美国", "英国"])# 添加y轴数据# 设置数值标签在又侧 bar.add_yaxis("G…

使用 docker 搭建 granfana+prometheus 监控平台监控测试服务器资源

互联网发展的今天&#xff0c;人们对互联网产品的用户体验要求也越来越高&#xff0c;企业为了能提供更优质的用户体验&#xff0c;就会绞尽脑汁想尽各种办法。而对于服务器的资源监控&#xff0c;搭建一个资源监控平台&#xff0c;就是一个很好的维护优质服务的保障平台。利用…

LLMs之Code:SQLCoder的简介、安装、使用方法之详细攻略

LLMs之Code&#xff1a;SQLCoder的简介、安装、使用方法之详细攻略 目录 SQLCoder的简介 1、结果 2、按问题类别的结果 SQLCoder的安装 1、硬件要求 2、下载模型权重 3、使用SQLCoder 4、Colab中运行SQLCoder 第一步&#xff0c;配置环境 第二步&#xff0c;测试 第…

Mac Flutter web环境搭建

获取 Flutter SDK 下载以下安装包来获取最新的 stable Flutter SDK将文件解压到目标路径, 比如: cd ~/development $ unzip ~/Downloads/flutter_macos_3.13.0-stable.zip 配置 flutter 的 PATH 环境变量&#xff1a; export PATH"$PATH:pwd/flutter/bin" // 这个命…

【1++的数据结构】之AVL树

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的数据结构】 文章目录 一&#xff0c;什么是AVL树二&#xff0c;AVL树的插入三&#xff0c;AVL树的旋转3.1 向左旋转3.2 向右旋转3.3 左右双旋3.4 右左双旋 四&#xff0c;验证AVL树是否平衡 …

LinkedList的顶级理解

目录 1.LinkedList的介绍 LinkedList的结构 2.LinkedList的模拟实现 2.1创建双链表 2.2头插法 2.3尾插法 2.4任意位置插入 2.5查找关键字 2.6链表长度 2.7遍历链表 2.8删除第一次出现关键字为key的节点 2.9删除所有值为key的节点 2.10清空链表 2.11完整代码 3.…

①matlab的命令掌握

目录 输入命令 命名变量 保存和加载变量 使用内置的函数和常量 输入命令 1.您可以通过在命令行窗口中 MATLAB 提示符 (>>) 后输入命令 任务 使用命令 3*5 将数值 3 和 5 相乘。 答案 3*5 2.除非另有指定&#xff0c;否则 MATLAB 会将计算结果存储在一个名为 ans…

POI groupRow 折叠分组,折叠部分不显示问题

折叠组是什么&#xff1f;如图就是用POI 实现的&#xff0c;代码很简单&#xff1a;sheet.groupRow(开始行&#xff0c;结束行)即可 但是万万没想到&#xff0c;最终实现出的结果&#xff0c;合并的组&#xff0c;有一部分并没有渲染出来&#xff0c;如下图&#xff1a; 因为我…

基于蜜獾算法优化的BP神经网络(预测应用) - 附代码

基于蜜獾算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于蜜獾算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.蜜獾优化BP神经网络2.1 BP神经网络参数设置2.2 蜜獾算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…

Android——基本控件(下)(十九)

1. 菜单&#xff1a;Menu 1.1 知识点 &#xff08;1&#xff09;掌握Android中菜单的使用&#xff1b; &#xff08;2&#xff09;掌握选项菜单&#xff08;OptionsMenu&#xff09;的使用&#xff1b; &#xff08;3&#xff09;掌握上下文菜单&#xff08;ContextMenu&am…

【会议征稿】2023智能通信与网络国际学术会议(ICN 2023)

2023智能通信与网络国际学术会议&#xff08;ICN 2023&#xff09; 2023 International Conference on Intelligent Communication and Networking (ICN2023) 2023智能通信与网络国际学术会议&#xff08;ICN 2023&#xff09;将于2023年11月10-12日在中国常州召开。ICN 2023…

Vue3+TS+Vite中 vConsole 插件的使用

平时在web应用开发过程中&#xff0c;我们可以console.log去输出一些信息&#xff0c;但是在移动端&#xff0c;也就是在手机上&#xff0c;console.log的信息我们是看不到的&#xff0c;这时候就需要移动端调试工具vConsole 1. 依赖安装 npm install vconsole 或者 yarn ad…

扫雷小游戏

目录 一.扫雷小游戏 二.游戏主体一览 ​编辑 三.模块化设计扫雷游戏 3.1打印欢迎菜单 3.2创建两个二维数组 3.3棋盘稍加修改 3.4布置雷 3.5排查雷 四.游戏总体代码 4.1game.h头文件 4.2game.c函数实现源文件 4.3游戏main函数主体 五.游戏效果图 一.扫雷小游戏 这是…

Jmeter+ServerAgent

一、Jmeter 下载 https://jmeter.apache.org/download_jmeter.cgi选择Binaries二进制下载 apache-jmeter-5.6.2.tgz 修改配置文件 jmeter下的bin目录&#xff0c;打开jmeter.properties 文件 languagezh_CN启动命令 cd apache-jmeter-5.6/bin sh jmeter二、ServerAgent 监…

实战 图书馆系统管理案例

config &#xff1a;敏感的配置一般都是在配置中心配置&#xff0c;比如consul或者阿波罗上面controller &#xff1a;写一些handler的&#xff0c;拿到参数要去调用service层的逻辑。&#xff08;只负责接受参数&#xff0c;怎么绑定参数&#xff0c;要去调用哪个service的&am…

Viobot输出数据说明

一.原始数据 1.ROS话题 1)相机原始图像数据 Type: sensor_msgs::Image Topic: 左目&#xff1a;/image_left 右目&#xff1a;/image_right 2&#xff09;imu数据 Type: sensor_msgs::Imu Topic: /imu 3&#xff09;TOF数据 点云数据&#xff1a; Type: sensor_msgs::P…

算法与数据结构(十)--图的入门

一.图的定义和分类 定义&#xff1a;图是由一组顶点和一组能够将两个顶点连接的边组成的。 特殊的图&#xff1a; 1.自环&#xff1a;即一条连接一个顶点和其自身的边; 2.平行边&#xff1a;连接同一对顶点的两条边&#xff1b; 图的分类&#xff1a; 按照连接两个顶点的边的…

带你速览主数据管理(MDM)的前世今生

主数据管理的历史可以追溯到很久以前&#xff0c;可以说主数据管理是生产生活的一部分。随着社会生产力和生产工具的不断发展&#xff0c;主数据和主数据管理在其中的作用不断提升&#xff0c;成为当今政府、企业和社会团队等组织管理中必不可少基础管理工作&#xff0c;同时也…

FrameBuffer 应用编程

目录 什么是FrameBufferLCD 的基础知识使用ioctl()获取屏幕参数信息使用mmap()将显示缓冲区映射到用户空间 LCD 应用编程练习之LCD 基本操作LCD 应用编程练习之显示BMP 图片BMP 图像介绍在LCD 上显示BMP 图像在开发板上测试 在LCD 上显示jpeg 图像在LCD 上显示png 图片LCD 横屏…