【Spring 】了解Spring AOP

目录

一、什么是Spring AOP

二、AOP的使用场景

三、AOP组成

四、Spring AOP的实现

1、添加Spring AOP依赖

2、定义切面和切点

3、定义相关通知

五、 AOP的实现原理

1、什么是动态代理 

2、 JDK代理和CGLIB代理的区别


一、什么是Spring AOP

AOP(Aspect Oriented Programming),直译过来就是面向切面编程,AOP是一种编程思想,是面向对象编程(OOP)的一种补充。Spring AOP是AOP思想的一种实现,就像DI一样是IoC的一种实现。

AOP的主要作用就是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点,减少对业务代码的侵入。增强代码的可读性和可维护性简单来所,AOP的作用就是保证开发者在不修改业务代码的前提下,位系统中的业务组件添加某种通用功能。

就比如实现一个用户登录权限的校验功能,就比如我们使用的博客,在要进入博客编辑的页面时,需要对你是否登录进行校验,如果已经登录,那么就可以进入编辑页,如果没有那么就需要在登录页面登录之后在进入。像这样需要登录校验的页面,我们使用AOP思想,只需要在某一处配置以下,所有的需要判断用户登录的页面就可以实现用户登录验证了。这样每个页面就只关注具体的业务逻辑了。

二、AOP的使用场景

就像上面举的例子,当你的程序中实现的页面越来越多,那么你要 写的登录验证也越来越多,⽽这些⽅法⼜是相同的,这么多的⽅法就会代码修改和维护的成本我们对这种功能统一,并且使用地方较多的功能,就可以考虑使用AOP来统一处理。当然AOP可以使用的场景还有很多。

  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交等

如果没有使用AOP思想来写代码,用户发送的请求直接被业务代码控制层接收到,请求访问的页面来校验用户是否登录。使用了AOP思想的代码,用户发送方的请求被AOP这里的代码先进行登录校验,如果登录,将请求传给控制层,如果没有登录就会被拦截。

三、AOP组成

1️⃣切面(Aspect):表示当前AOP是针对那些事件做处理的,用来登录的还是记录日志的。切面就是通知和切点的结合,通知和切点共同定义了切面的全部内容,他是干什么的,什么时候在哪里执行。通常以类的形式表示。

2️⃣切点(Pointcut):表示定义具体规则。切点其实就是筛选出的连接点,一个类中的所有方法都是连接点,但又不全需要,会筛选出某些作为连接点作为切点,如果说通知定义了切面的动作后者执行时机的话,切点则定义了执行的地点。

3️⃣通知(Advice):AOP执行的具体方法。有的地方叫增强。

4️⃣连接点(Join point):就是有可能触发切点的所有点。应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,异常抛出时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

四、Spring AOP的实现

1、添加Spring AOP依赖

在创建好的Spring Boot项目的pom.xml中添加Spring AOP的依赖,我们可以从中央仓库中下载

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

然后点击刷新,触发下载。

2、定义切面和切点

这里使用注解@Aspect表示定义切面,即UserAserAspect类为切面,使用@Component注解表示让切面随着框架的启动而启动,这样切面中的切点定义的拦截规则才能生效。

package com.example.demo.common;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect//定义切面
@Component//让切面随着框架的启动而启动
public class UserAspect {
    //定义切点,@Pointcut注解的参数中定义了具体的拦截规则。参数中使用AspectJ表达式语法
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut(){}
}

上述代码中,pointcut方法为空方法,它不需要又方法体,此方法名就是起到一个"标识"的作用,标识下面的通知方法具体指的是那个切点。因为一个切面中有很多切点。

上述pointcut方法上添加的@Pointcut注解的参数中使用切点表达式定义了具体的拦截规则

execution(* com.example.demo.controller.UserController.*(..))

切点表达的意思是拦截UserContrller类中的所有方法其参数为任意参数并且返回值为任意类型的返回值。

  • execution表示的意思为执行,执行的是后面跟的()中的规则。
  • *表示的多个部分组成的,有修饰符和返回值类型。
  • com.example.demo.controller.UserController表示要拦截com.example.demo.controller包中的UserController类
  • 类后面跟的*表示UserController类中的所有方法。
  • ..表示的不定式传参

切点表达式由切点函数组成,其中execution()最常见的切点函数用来匹配方法,语法为:

execution(<修饰符><返回值类型><包.类.方法(参数)><异常>)

常见表达式示例

  • execution(* com.example.demo.User.*(..)):匹配User类中的所有方法。
  • execution(* com.example.demo.User+.*(..)):匹配该类的子类包括该类的所有方法
  • execution(* com.example.*.*(..)):匹配com.example包下的所有类的所有方法
  • execution(* com.example..*.*(..)):匹配com.example包下,子孙包下所有类的所有方法
  • execution(* addUser(String,int)):匹配addUser方法,其第一个参数类型是String,第二个参数类型是int。

创建UserController类,这个类中的方法哪一个要被执行(目标方法)哪一个就是连接点

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/getuser")
    public String getUser(){
        System.out.println("do getUser");
        return "get user";
    }
    @RequestMapping("/deluser")
    public String delUser(){
        System.out.println("do delUser");
        return "del user";
    }
}

3、定义相关通知

通知定义的是被拦截的方法具体要执行的业务。比如用户登录权限验证方法就是具体要执行的业务。

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

  • 前置通知使用@Before:通知方法会在目标方法(连接点)调用之前执行
  • 后置通知使用@After:通知方法会在目标方法(连接点)返回或者抛出异常后调用
  • 返回之后通知使用@AfterReturning:通知方法会在目标方法(连接点)返回后调用
  • 抛异常后通知使用@AfterThrowing:通知方法会在目标方法(连接点)抛出异常后调用
  • 环绕通知使用@Around:通知包裹了被通知的方法,在被通知的方法之前和调用之后执行自定义的行为。

1️⃣前置通知和后置通知的实现

package com.example.demo.common;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect//定义切面
@Component//让切面随着框架的启动而启动
public class UserAspect {
    //定义切点,@Pointcut注解的参数中定义了具体的拦截规则
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut(){}

    //定义前置通知
    @Before("pointcut()")//表示这个通知是针对pointcut方法的
    public void doBefore(){
        System.out.println("执行了前置通知");
    }

    //定义后置通知
    @After("pointcut()")
    public void doAfter(){
        System.out.println("执行了后置通知");
    }
}

当我们在前端页面中访问UserController类的方法时,后端程序的控制台上每次出现的结果是先执行前置通知,在执行目标方法(连接点),然后执行后置通知。

 

2️⃣环绕通知的具体实现 

环绕通知方法是具有Object类型的返回值,需要把方法执行结果返回给框架,框架拿到对象继续执行。

package com.example.demo.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect//定义切面
@Component//让切面随着框架的启动而启动
public class UserAspect {
    //定义切点,@Pointcut注解的参数中定义了具体的拦截规则
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut(){}

    //定义前置通知
    @Before("pointcut()")//表示这个通知是针对pointcut方法的
    public void doBefore(){
        System.out.println("执行了前置通知");
    }

    //定义后置通知
    @After("pointcut()")
    public void doAfter(){
        System.out.println("执行了后置通知");
    }

    //定义环绕通知
    @Around("pointcut()")
    //环绕通知方法的参数为要执行的连接点,也就是我们在前端访问的目标方法
    public Object doAround(ProceedingJoinPoint joinPoint){
        System.out.println("环绕通知之前");
        Object result = null;
        try {
            //执行目标方法,它的目标方法就是我们在前端访问的方法
            result = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("环绕通知之后");
        return result;
    }
}

从执行结果中可以看到环绕通知的执行范围,可以环绕执行通知是最先执行的,然后是执行前置通知,然后再执行目标方法,然后执行后置通知,最后所有的方法执行完成了,环绕通知方法才会执行完成。

 

五、 AOP的实现原理

Spring AOP是建立再动态代理的基础上的,Spring对AOP的支持局限于方法级别的拦截。

Spring AOP使用两种混合的实现方式:JDK动态代理和CGLib动态代理。

  • JDK动态代理:如果目标对象实现了InvocationHandler接口,Spring将使用JDK动态代理来创建代理对象。
  • CGLib动态代理:如果目标对象没有实现InvocationHandler接口,Spring将使用CGLib代理,通过继承目标对象来创建代理对象。

1、什么是动态代理 

代理可以看作是对调用目标的一个包装,这样我们对目标代理的调用不是直接发生的,而是通过代理完成。

当想要给实现了某个接口的类中的方法,加一些额外的处理,比如加日志,加事务等。可以给这个类创建一个代理,也就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新方法,这个代理类并不是定义好的,而是动态生成的,具有解耦意义,灵活、扩展性强。

在Java中,动态代理通常使用Java.lang.reflect.Proxy类和Java.lang.reflect.InvocationHandler接口来实现。

2、 JDK代理和CGLIB代理的区别

  • 接口要求:JDK动态代理只能对实现了接口的类生成代理;而CGLIB代理可以没有实现接口的类,是通过继承被代理类,在运行时动态的生成代理对象。
  • 生成方式:JDK代理使用Java的反射机制来完成代理对象,而CGLIB代理使用CGLIB库生成代理对象,通过修改目标类的字节码来实现。所以该类不能被final修饰

如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
 

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

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

相关文章

opencv-进阶05 手写数字识别原理及示例

前面我们仅仅取了两个特征维度进行说明。在实际应用中&#xff0c;可能存在着更多特征维度需要计算。 下面以手写数字识别为例进行简单的介绍。 假设我们要让程序识别图 20-2 中上方的数字&#xff08;当然&#xff0c;你一眼就知道是“8”&#xff0c;但是现在要让计算机识别…

SharkTeam:Worldcoin运营数据及业务安全分析

Worldcoin的白皮书中声明&#xff0c;Worldcoin旨在构建一个连接全球人类的新型数字经济系统&#xff0c;由OpenAI创始人Sam Altman于2020年发起。通过区块链技术在Web3世界中实现更加公平、开放和包容的经济体系&#xff0c;并将所有权赋予每个人。并且希望让全世界每一个人都…

【iMessage频發软件苹果群发技术开源原创】当 APNs 发送通知到一个离线设备时,APNs 会把通知存储起来(一定的时间内),当设备上线时再递送给设备。

推荐内容IMESSGAE相关 作者✈️IMEAE推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容3.日历推 *** …

ATTCK覆盖度97.1%!360终端安全管理系统获赛可达认证

近日&#xff0c;国际知名第三方网络安全检测服务机构——赛可达实验室&#xff08;SKD Labs&#xff09;发布最新测试报告&#xff0c;360终端安全管理系统以ATT&CK V12框架攻击技术覆盖面377个、覆盖度97.1%&#xff0c;勒索病毒、挖矿病毒检出率100%&#xff0c;误报率0…

数据分析 | 随机森林如何确定参数空间的搜索范围

1. 随机森林超参数 极其重要的三个超参数是必须要调整的&#xff0c;一般再加上两到三个其他超参数进行优化即可。 2. 学习曲线确定n_estimators搜索范围 首先导入必要的库&#xff0c;使用sklearn自带的房价预测数据集&#xff1a; import numpy as np import pandas as pd f…

Java数字化智慧工地管理云平台源码(人工智能、物联网、大数据)

智慧工地优势&#xff1a;"智慧工地”将施工企业现场视频管理、建筑起重机械安全监控、现场从业人员管理、物料管理、进度管理、扬尘噪声监测等现场设备有机、高效、科学、规范的结合起来真正实现工程项目业务流与现场各类监控源数据流的有效结合与深度配合&#xff0c;实…

css3-grid:grid 布局 / 基础使用

一、理解 grid 二、理解 css grid 布局 CSS Grid布局是一个二维的布局系统&#xff0c;它允许我们通过定义网格和网格中每个元素的位置和尺寸来进行页面布局。CSS Grid是一个非常强大的布局系统&#xff0c;它不仅可以用于构建网格布局&#xff0c;还可以用于定位元素&#xf…

解锁编程的新契机:深入探讨Kotlin Symbol Processor (KSP)的编写

解锁编程的新契机&#xff1a;深入探讨Kotlin Symbol Processor (KSP)的编写 1. 引言 随着软件开发领域的不断发展&#xff0c;新的工具和技术不断涌现&#xff0c;以满足开发者在构建高效、可维护和创新性的代码方面的需求。Kotlin Symbol Processor&#xff08;KSP&#xf…

Actuator微服务信息完善-Eureka—SpringCloud(版)微服务学习教程(11)

一、Actuator是什么&#xff1f; Actuator是Springboot提供的用来对应用系统进行自省和监控的功能模块&#xff0c;借助于Actuator开发者可以很方便地对应用系统某些监控指标进行查看、统计等。 在Springboot中使用Actuator监控非常简单&#xff0c;只需要在工程POM文件中引入…

VMware虚拟安装Ubuntu,然后切换Ubuntu内核版本

无论你选择哪种方法&#xff0c;一旦进入 GRUB 引导菜单&#xff0c;你应该能够选择需要的内核版本并启动系统。 打开终端&#xff1a;你可以通过按下 Ctrl Alt T 快捷键来打开终端。 使用 sudo&#xff1a;切换内核需要管理员权限&#xff0c;因此你需要使用 sudo 命令。首…

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;可以通过直接或者文件操作方式进行读写。不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xf…

[C初阶笔记]P2

Git 1、Git是Linus为了帮助管理Linux内核开发 而开发的一个开放源码的分布式版本控制软件。 2、Git和TortoiseGit的作用。 Git中有各种命令行操作&#xff0c;来维护代码&#xff0c;可以将代码推送到代码托管平台。 TortoiseGit是将Git中各自命令行操作转化为图形化操作。 …

C语言好题解析(一)

目录 选择题1选择题2选择题3选择题4编程题一 选择题1 执行下面程序&#xff0c;正确的输出是&#xff08; &#xff09;int x 5, y 7; void swap() {int z;z x;x y;y z; } int main() {int x 3, y 8;swap();printf("%d,%d\n",x, y);return 0; }A: 5,7 B: …

Threejs学习03——实现随机多个三角形随机位置随机颜色展示效果

实现随机多个三角形随机位置随机颜色展示效果 这是一个非常简单基础的threejs的学习应用&#xff01;本节主要介绍的是随机&#xff0c;随机位置以及随机颜色&#xff0c;我们使用的物体是三角形&#xff0c;通过一个三角形三个顶点每一个顶点通过xyz坐标来确定&#xff0c;则…

Java算法_ 检查对称树(LeetCode_Hot100)

题目描述&#xff1a;给你一个二叉树的根节点 &#xff0c; 检查它是否轴对称。root 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 /*** 2 * Author: LJJ* 3 * Date: 2023/8/17 8:47* 4*/ public class SymmetricTree {static class…

智慧水利利用4G物联网技术实现远程监测、控制、管理

智慧水利工业路由器是集合数据采集、实时监控、远程管理的4G物联网通讯设备&#xff0c;能够让传统水利系统实现智能化的实时监控和远程管理。工业路由器利用4G无线网络技术&#xff0c;能够实时传输数据和终端信息&#xff0c;为水利系统的运维提供有效的支持。 智慧水利系统是…

Linux知识点 -- Linux多线程(一)

Linux知识点 – Linux多线程&#xff08;一&#xff09; 文章目录 Linux知识点 -- Linux多线程&#xff08;一&#xff09;一、理解线程1.从资源角度理解线程2.执行流3.多线程编程4.线程的资源5.线程切换的成本更低6.线程的优缺点7.线程异常 二、线程控制1.clone函数2.线程异常…

Unity如何把游戏导出成手机安装包

文章目录 前言使用环境步骤添加场景构建APK 前言 本文章主要演示了&#xff0c;如何将制作好的游戏&#xff0c;导出成APK&#xff0c;安装到手机上。 使用环境 Unity2022。 步骤 首先打开你的项目&#xff0c;然后选择菜单栏的“File” > “Build Settings…”&#xf…

时序预测 | MATLAB实现基于CNN-BiLSTM卷积双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于CNN-BiLSTM卷积双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于CNN-BiLSTM卷积双向长短期记忆神经网络的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍…

【使用 k 折叠交叉验证的卷积神经网络(CNN)】基于卷积神经网络的无特征EMG模式识别研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…