7、Spring_AOP

news2024/12/26 11:55:16

一、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 配置作为了解内容即可

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

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

相关文章

常见前端面试之VUE面试题汇总六

17. MVVM 的优缺点? 优点: 分离视图&#xff08;View&#xff09;和模型&#xff08;Model&#xff09;&#xff0c;降低代码耦合&#xff0c;提⾼视图或者 逻辑的重⽤性: ⽐如视图&#xff08;View&#xff09;可以独⽴于 Model 变化和修改&#xff0c;⼀个 ViewModel 可以…

安防视频监控平台EasyCVR云存储平台基于云-端-边一体化结构在银行自助机ATM中的应用方案

随着银行ATM功能的不断完善和升级&#xff0c;人们对ATM的依赖和使用程度越来越高。然而&#xff0c;作为一个开放的公共环境&#xff0c;ATM在服务应用中容易出现各种异常情况和业务纠纷&#xff0c;一些不法分子也利用ATM进行犯罪活动。 对于银行用户来说&#xff0c;提前预警…

2021–2022年北京市丰台区典型自然保护地植物物种名录数据集

摘要 植物是自然保护地的核心组成,是维持生物多样性等生态系统功能发挥的基础资源。本文基于2021和2022年对北京市丰台区4处代表性的自然保护地(南苑森林湿地公园、绿堤公园、莲花池公园、北宫国家森林公园)中植物物种的实地调查结果,整理出丰台区典型自然保护地植物物种名…

人工智能开发板 SE5 - MB1684开发入门指南 -- 模型转换、交叉编译、开发板运行 yolov5 目标追踪

介绍 我们属于SoC模式&#xff0c;即我们在x86主机上基于tpu-nntc和libsophon完成模型的编译量化与程序的交叉编译&#xff0c;部署时将编译好的程序拷贝至SoC平台&#xff08;1684开发板/SE微服务器/SM模组&#xff09;中执行。 注&#xff1a;以下都是在Ubuntu20.04系统上操…

Unity 结构少继承多组合

为什么不推荐使用继承&#xff1f; 继承是面向对象的四大特性之一&#xff0c;用来表示类之间的 is-a 关系&#xff0c;可以解决代码复用的问题。虽然继承有诸多作用&#xff0c;但继承层次过深、过复杂&#xff0c;也会影响到代码的可维护性。所以&#xff0c;对于是否应该在…

论文详解——《Deep Color Consistent Network for Low-Light Image Enhancement》

文章目录 Abstract3. Proposed Method3.1 Network Structure3.2. Pyramid Color Embedding (PCE)3.3. Objective Function Abstract 微光图像增强(LLIE)研究了如何细化光照&#xff0c;获得自然的正常光照图像。目前的LLIE方法主要侧重于提高光照&#xff0c;而没有合理地将颜…

手机锁屏密码忘了怎么解开?4个方法,帮你解锁!

“最近新买了一部手机&#xff0c;为了保护隐私我还特意设置了密码。明明之前一直都记得&#xff0c;但昨天手机没电后重新开机&#xff0c;就怎么也想不起手机的锁屏密码了&#xff0c;有什么方法可以解决这个问题吗&#xff1f;” 随着手机在日常生活中的普及&#xff0c;手机…

uCharts 运行微信小程序时,图表放在scroll-view中点击后不能正确获取点击的currentIndex一直为-1

图表在APP和H5中的点击位置是正常的,在微信小程序中会出现点击位置不对且有部分地方点击不到,最终我的解决方法如下。 1.查看包裹图表的元素中有没有元素开启了定位,可以去除定位属性试一试。 2.为微信平台的图表添加 isScrollView="true"属性。 解决方案: 添加 …

极狐GitLab 价值流管理之「总时间图」使用指南

本文来源&#xff1a;about.gitlab.com 作者&#xff1a;Haim Snir 译者&#xff1a;极狐(GitLab) 市场部内容团队 对于软件研发管理者来说&#xff0c;了解在整个研发过程中时间都耗费在了哪些地方&#xff0c;是进行交付价值优化的关键洞察。GitLab / 极狐GitLab 新的价值流分…

基于ssm校园快递代取系统源码和论文

基于ssm校园快递代取系统源码和论文056 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;…

视频云存储平台EasyCVR视频汇聚平台关于机电设别可视化管理平台可实施设计方案

随着工业化进程的不断发展&#xff0c;机电设备在各行各业中扮演着重要的角色。然而&#xff0c;由于机电设备种类繁多、数量庞大&#xff0c;包括生产机械、建筑器械、矿用器械、制药器械、食品机械等&#xff0c;传统的手动管理方式已经无法满足对设备进行精细化管理的需求。…

环球新材国际完成韩国CQV公司交割 国际化布局迈出里程碑式关键一步

8月23日&#xff0c;环球新材国际&#xff08;6616.HK&#xff09;发布公告&#xff0c;公司收购的全球著名珠光颜料企业韩国CQV公司已正式完成了交割程序及董事会改组。交割完成后&#xff0c;环球新材国际持有CQV已发行股份的42.45%&#xff0c;成为CQV的单一最大股东。CQV亦…

高手进阶之路---pyqt自定义信号

高手进阶之路—pyqt自定义信号 1.思考问题为什么要自定义信号&#xff0c;qt5本身已有信号槽函数 # pushButton 被clicked的时候connect 函数print self.pushButton.clicked.connect(self.print)def print(self):print("我被点击了")或者使用 # 需要引入 pyqtSlo…

Eplan 标准部件库(一)

一. 为什么要建立标准的部件库呢&#xff1f; 1. 提高质量。希望我们的数据更标准&#xff0c;更规范。 2. 数据完整。建立数据的完整度&#xff0c;让我们的数据可以支撑设计&#xff0c;生产&#xff0c;运维等各个方面的流程。 PLAN Data Portal是EPLAN软件的一个在线部件…

报错 The number of live datanodes 1 has reached the minimum number 0

报错 2023-08-24 09:24:59,227 ERROR org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode: Exception in doCheckpoint org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.SafeModeException): Log not rolled. Name node is in safe mo…

Server2016安装SQL server数据库遇到异常解决

首先看几个会出现的异常&#xff0c;下边看解决办法&#xff1a; 第一步: 先修改安装包x86\setup目录下的setupsql.exe,以Xp&#xff0c;SP3兼容模式运行&#xff0c; 这个右键&#xff0c;属性&#xff0c;兼容性&#xff0c;修改就行&#xff0c;类似这样 第二步: 修改c:…

k8s 安装 istio(二)

3.3 部署服务网格调用链检测工具 Jaeger 部署 Jaeger 服务 kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/jaeger.yaml 创建 jaeger-vs.yaml 文件 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata…

GEEMAP 基本操作(一)如何拉伸图像

图像拉伸是最基础的图像增强显示处理方法&#xff0c;主要用来改善图像显示的对比度&#xff0c;地物提取流程中往往首先要对图像进行拉伸处理。图像拉伸主要有三种方式&#xff1a;线性拉伸、直方图均衡化拉伸和直方图归一化拉伸。 GEE 中使用 .sldStyle() 的方法来进行图像的…

matlab中判断数据的奇偶性(mod函数、rem函数)

用Matlab判断一个数是偶数还是奇数 1、mod函数 X 25;%要判断的数 if mod(X,2)1disp(奇数);%奇数 elsedisp(偶数);%偶数 end结果 2、rem函数 n25; if rem(n,2)0display(偶数); elsedisplay(奇数); end结果

threejs贴图系列(一)canvas贴图

threejs不仅支持各种texture的导入生成贴图&#xff0c;还可以利用canvas绘制图片作为贴图。这就用到了CanvasTexture&#xff0c;它接受一个canas对象。只要我们绘制好canvas&#xff0c;就可以作为贴图了。这里我们利用一张图片来实现这个效果。 基础代码&#xff1a; impo…