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

  • 测试代码

    @Test
        public 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 配置作为了解内容即可

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

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

相关文章

华为云CodeArts Snap 智能编程助手PyCharm实验手册. 插件安装与使用指南

作为一款自主创新的AI代码辅助编程工具&#xff0c;华为云智能编程助手CodeArts Snap目标打造现代化开发新范式。通过将自然语言转化为规范可阅读、无开源漏洞的安全编程语言&#xff0c;提升开发者编程效率&#xff0c;助力企业快速响应市场需求。华为云CodeArts Snap现进入邀…

vue(element ui安装)

目录 一&#xff0c;element ui安装二&#xff0c;main.js三&#xff0c;使用element ui最后 一&#xff0c;element ui安装 先在盘服中找到你创建的node的位置 如有不懂根据可以看看上一章安装node 然后在终端找到 进入这个位置之后就可以安装了 输入npm i element-ui -S这个…

【BASH】回顾与知识点梳理(三十八)

【BASH】回顾与知识点梳理 三十八 三十八. 源码概念及简单编译38.1 开放源码的软件安装与升级简介什么是开放源码、编译程序与可执行文件什么是函式库什么是 make 与 configure什么是 Tarball 的软件如何安装与升级软件 38.2 使用传统程序语言进行编译的简单范例单一程序&#…

《Linux从练气到飞升》No.17 进程创建

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

Spring MVC详解

文章目录 一、SpringMVC1.1 引言1.2 MVC架构1.2.1 概念1.2.2 好处 二、开发流程2.1 导入依赖2.2 配置核心(前端)控制器2.3 后端控制器2.4 配置文件2.5 访问 三、接收请求参数3.1 基本类型参数3.2 实体收参【重点】3.3 数组收参3.4 集合收参 【了解】3.5 路径参数3.6 中文乱码 四…

JDK JRE JVM 三者之间的详解

JDK : Java Development Kit JRE: Java Runtime Environment JVM : JAVA Virtual Machine JDK : Java Development Kit JDK : Java Development Kit【 Java开发者工具】&#xff0c;可以从上图可以看出&#xff0c;JDK包含JRE&#xff1b;java自己的一些开发工具中&#…

容灾设备系统组成,容灾备份系统组成包括哪些

随着信息技术的快速发展&#xff0c;企业对数据的需求越来越大&#xff0c;数据已经成为企业的核心财产。但是&#xff0c;数据安全性和完整性面临巨大挑战。在这种环境下&#xff0c;容灾备份系统应运而生&#xff0c;成为保证企业数据安全的关键因素。下面我们就详细介绍容灾…

Vue3项目实战

目录 一、项目准备 二、基础语法应用 2.1、mixin应用 2.2、网络请求 2.3、显示与隐藏 2.4、编程式路由跳转 2.5、下载资料 2.6、调用方法 2.7、监听路由变化 2.8、pinia应用 (1)存储token(user.js) (2)全选全不选案例(car.js) 一、项目准备 下载&#xff1a; cnp…

Bigemap在地质工程勘察行业中的应用

1.选择Bigemap的原因&#xff1a; 师兄在测绘局工作&#xff0c;买过全能版&#xff0c;帮我下载过高程数据&#xff0c;我觉得效果可以&#xff0c;于是联系到软件公司进行试用、咨询 2.使用场景&#xff1a; 影像、等高线、地形等资料下载&#xff0c;下载完放进arcgis 软件&…

通俗理解拉格朗日乘数法

再理解拉格朗日乘数法 笔记来源&#xff1a;Understanding Lagrange Multipliers Visually 本人相关博客&#xff1a; 1.方向导数和梯度向量 2.最小二乘和回归线、拉格朗日乘数、二元泰勒多项式、带约束变量的偏导数 函数&#xff1a; z f ( x , y ) zf(x,y) zf(x,y)&#x…

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.…

蓝蓝设计ui设计公司作品--泛亚高科-光伏电站控制系统界面设计

泛亚高科(北京)科技有限公司&#xff08;以下简称“泛亚高科”&#xff09;&#xff0c;一个以实时监控、高精度数值计算为基础的科技公司&#xff0c; 自成立以来&#xff0c;组成了以博士、硕士为核心的技术团队&#xff0c;整合了华北电力大学等高校资源&#xff0c;凭借在电…

运算放大器发展史

在内部集成了一个补偿电容 MPS公司OP07推出后&#xff0c;大受欢迎。各家厂商都推出了自己的 这4款都是可以替换的

Linux搭建SSLVpn

安装http、ssl服务 编辑http配置文件 修改http的136行&#xff0c;276行以及990行 1、136行将监听端口注释 2、276行和990行修改为自己的域名和要访问的端口 修改http文档最后那部分 新添ssl配置信息&#xff0c;将端口修改为443&#xff08;截图错了server.key应该放在/etc/…

告别gazebo开启长时间等待 设置gazebo打开不再联网找模型

学过ros的对gazebo仿真软件应该都不会陌生&#xff0c;但是有时启动真的很烦人&#xff0c;经常卡在这个地方很长时间&#xff0c;查阅资料 gazebo软件开启的时候会自动从国外官网下载模型&#xff0c;因此这个过程比较漫长&#xff0c;原因是网站在国外&#xff0c;下载不顺畅…

GaussDB数据库SQL系列:DROP TRUNCATE DELETE

目录 一、前言 二、GaussDB的 DROP & TRUNCATE & DELETE 简述 1、命令简述 2、命令比对 三、GaussDB的DROP TABLE命令及示例 1、功能描述 2、语法 3、示例 四、GaussDB的TRUNCATE命令及示例 1、功能描述 2、语法 3、示例 4、示例 五、GaussDB的DELETE命令…

【AWS】安装配置适用于 Eclipse 的 AWS 工具包

目录 0.环境 1.步骤 1&#xff09;安装Eclipse 2&#xff09;安装AWS工具包 ① 在这个路径下点开安装软件的界面 ② 点击【Add】打开添加窗口 ③ 输入aws的工具包地址 ④ 勾选需要的工具&#xff0c;点击【Next】 ⑤ 将要安装的工具&#xff0c;点击【Next】 ⑥ 选择接受…

【Linux网络】Cookie和session的关系

目录 一、Cookie 和 session 共同之处 二、Cookie 和 session 区别 2.1、cookie 2.2、session 三、cookie的工作原理 四、session的工作原理 一、Cookie 和 session 共同之处 Cookie 和 Session 都是用来跟踪浏览器用户身份的会话方式。 二、Cookie 和 session 区别 2.…

R包开发1:RStudio 与 GitHub建立连接

目录 1.安装Git 2-配置Git&#xff08;只需配置一次&#xff09; 3-用SSH连接GitHub(只需配置一次) 4-创建Github远程仓库 5-克隆仓库到本地 目标&#xff1a;创建的R包&#xff0c;包含Git版本控制&#xff0c;并且能在远程Github仓库同步&#xff0c;相当于发布在Github。…

Nexus2迁移升级到Nexus3

与 Nexus 2.x 相比&#xff0c;Nexus 3.x 为我们提供了更多实用的新特性。SonaType 官方建议我们&#xff0c;使用最新版本 Nexus 2.x 升级到最新版本 Nexus 3.x&#xff0c;并在 Nexus 升级兼容性 一文中为我们提供了各个版本 Nexus 升级到最新版本 Nexus 3.x 的流程&#xff…