当前位置: 首页 > news >正文

Spring之AOP理解及使用

文章目录

      • AOP是什么
      • AOP
        • Spring的通知类型
            • 1.Before通知
            • 2. AfterReturning通知
            • 3.AfterThrowing通知
            • 4. After通知
            • 5. Around通知
        • 动态代理
          • JDK动态代理
          • CGLib动态代理
          • 动态代理的代码展示
      • AOP使用
        • 切面类的配置
      • 最后

大家好,我是Leo!今天给大家带来的是关于Spring AOP的一些知识和动态代理的两种实现方式,以及AOP的使用,希望大家可以喜欢👍👍👍

AOP是什么

AOP:面向切面编程,简单的说,就是把一些业务逻辑中的相同代码抽取到一个独立的模块中,让业务逻辑更加清楚,耦合性更低。

AOP

切面(Aspect):描述的是一个应用系统的某一方面或领域,如日志、事务、权限检查等。切面和类非常相似,对连接点、切入点、通知及类型间声明进行封装。

连接点(Joinpoint):连接点是应用程序执行过程中插入切面的点,这些点可能是方法的调用、异常抛出或字段的修改。Spring只支持方法的Joinpoint,也就是Advice将方法执行的前后被应用

通知(Advice):表示切面的行为,具体表现位实现逻辑的一个方法,常见的方法有Before、After、Around和Throws。Before和After分别表示通知在连接点的前面或者后面执行,Around则表示在连接点的外面执行,并可以决定是否执行此连接点。Throws通知方法抛出异常时执行。

切入点(Pointcut):切入点指定了通知应用在哪些连接点上,Pointcut切点通过正则表达式定义方法集合。切入点由一系列切入点指示符通过逻辑运算组合得到,AspectJ的常用切入点指示符包括execution、call、inititalization、handler、get、set、this、target、args、within等

目标对象(Target): 目标对象是指被通知的对象,它是一个普通的业务对象,如果没有AOP,那么它其中可能包含打量的非核心业务逻辑代码,如日志、事务等;而如果使用了AOP,则其中只有核心的业务逻辑代码。

代理(Proxy):代理是指通知应用到目标对象后形成的新的对象。

织入(Weraving): 织入是指将切面应用到目标对象而建立一个新的代理对象的过程,切面在指定的接入点被织入目标对象中。

Spring的通知类型

1.Before通知

Before通知处理前,该方法还未执行,所以使Before通知无法返回目标方法的值

2. AfterReturning通知

在切点表达式中定义的方法后执行

pointcut/value:这两个属性是一样的,用来指定切入点对呀的切入点表达式,可以是已定义的切入点,也可直接定义切入点表达式

returning:指定一个返回值的形参名,可以通过该形参可访问目标方法的返回值

3.AfterThrowing通知

主要用来处理程序中未处理的异常。使用AfterThrowing通知可指定如下属性。

pointcut/value:用来指定切入点对应的切入点表达式

throwing:指定一个返回形参名,通过该形参访问目标方法抛出但未处理的异常。

4. After通知

与AfterReturning通知非常类似,但是AfterReturning通知只有在目标方法执行完毕才可以被织入

5. Around通知

这个功能比较强大,近似等于Before通知和AfterReturning通知的总合,但是Around通知可以决定目标方法什么时候执行,如何执行。

在定义Around通知的切面逻辑方法时,必须给方法加入ProceedingJoinPoint类型的参数,在方法内调用ProceedingJoinPoint的proceed()方法才会执行目标方法。

优先级由低到高的顺序

Before通知–》Around通知–》AterReturning通知 --》After通知 /AfterThrowing通知

动态代理

动态代理就是,在程序运行期创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。

Spring AOP是通过动态代理实现的,动态代理主要有两种方式JDK动态代理和CGLib动态代理,这两种动态代理的使用和原理有些不同。

JDK动态代理

基于接口的动态代理

  1. 对于JDK代理,目标类需要实现一个Interface

  2. InvocationHandler是一个接口,可以实现这个接口,再通过调用反射机制(invoke)调用目标类的代码

  3. Proxy可以使用newProxyInstance,传入类加载器,目标的接口,InvocationHandler,生成一个动态代理的对象

CGLib动态代理

基于类的动态代理

  1. JDK代理的一大限制是只能为接口创建代理实例,CgLib没有这个限制

  2. CgLib创建的动态代理对象性能比JDK性能要高

  3. CgLib是基于ASM实现,通过字节码技术为一个类创建子类,在子类中采用方法拦截父类方法的调用

两种动态代理的图如下,可以很清楚看出JDK代理是需要实现接口,而CgLib不需要。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z7UCAVtP-1677496876494)(D:\卓面\学习文件\学习内容\博客\博客插图\JDK动态代理.drawio.png)]

动态代理的代码展示

JDK动态代理

public class ProxyFactory {private Object target;public ProxyFactory(Object target) {this.target = target;}public Object getProxy() {ClassLoader classLoader = target.getClass().getClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();InvocationHandler invocationHandler = new InvocationHandler() {/**** @param proxy 代理对象* @param method 代理需要实现的方法* @param args 参数* @return 返回值* @throws Throwable 抛出的异常*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 调用目标的方法Object result = null;try {System.out.println("[动态代理][日志] "+ method.getName()+",参数:"+ Arrays.toString(args));result = method.invoke(target, args);System.out.println("[动态代理][日志] "+ method.getName()+",结果:"+ result);} catch (Exception e) {e.printStackTrace();System.out.println("[动态代理][日志] "+ method.getName()+",异常:"+ e.getMessage());} finally {System.out.println("[动态代理][日志] "+ method.getName()+",方法执行完毕");}return result;}};/*** Proxy.newProxyInstance* 三个参数* 1. 加载动态生成代理类来加载的类加载器* 2. interfaces: 目标对象实现的所有接口class类型数组* 3. InvocationHandler 设置代理对象实现对象方法的过程*/return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);}
}

CgLib动态代理

public class ProxyCglibFactory implements MethodInterceptor {private Object target;public ProxyCglibFactory(Object target) {this.target = target;}public Object getProxyInstance() {Enhancer enhancer = new Enhancer();// 设置父类enhancer.setSuperclass(target.getClass());// 设置回调函数enhancer.setCallback(this);// 创建子类对象处理return enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 调用目标的方法Object result = null;try {System.out.println("[动态代理][日志] "+ method.getName()+",参数:"+ Arrays.toString(args));result = method.invoke(target, args);System.out.println("[动态代理][日志] "+ method.getName()+",结果:"+ result);} catch (Exception e) {e.printStackTrace();System.out.println("[动态代理][日志] "+ method.getName()+",异常:"+ e.getMessage());} finally {System.out.println("[动态代理][日志] "+ method.getName()+",方法执行完毕");}return result;}
}

AOP使用

AOP切面这些概念的定义是比较抽象的,下面我们来看一下如何使用。

假设一个场景,我有一个计算器类有加减乘除四个方法,我想要打印每一个方法的参数和对应的返回值。

有人就说啦,我每一个System.out.println,或者log.info不就行了嘛,但是加入有一百个方法呢,不断复制CV是不是多余的?

Calculator.java

public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);}
@Component
public class CalculatorImpl implements Calculator {@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法内部 result = " + result);return result;}
}

切面类的配置

@Component
@Aspect
public class LogAspect {/*** 设置切入点和通知类型* 切入点表达式 execution(访问修饰符 返回值类型 方法所在类的全路径 方法名 参数列表* 通知类型:* 前置@Before* 返回@AfterReturning* 异常@AfterThrowing* 后置@After* 环绕@Around()*/@Before(value = "pointCut()")public void beforeMethod(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("Logger-->前置通知,方法名称:" + methodName + "参数:" + Arrays.toString(args));}@After(value = "pointCut()")public void afterMethod(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->后置通知,方法名称:" + methodName);}@AfterReturning(value = "pointCut()", returning = "result")public void afterReturningMethod(JoinPoint joinPoint, Object result) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回前置通知,方法名称:" + methodName + "返回值:" + result.toString());}@AfterThrowing(value = "pointCut())", throwing = "exception")public void afterThrowingMethod(JoinPoint joinPoint, Throwable exception) {String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->异常通知,方法名称:" + methodName + "异常:" + exception.toString());}@Around(value = "pointCut()")public Object aroundMethod(ProceedingJoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();String argsString = joinPoint.getArgs().toString();Object result = null;try {System.out.println("环绕通知");// 调用目标方法result = joinPoint.proceed();System.out.println("环绕通知==目标方法返回值之后");} catch (Throwable ex) {System.out.println("环绕通知==目标方法出现异常之后");} finally {System.out.println("环绕通知==目标方法执行完毕");}return result;}/*** 重用切入点表达式*/@Pointcut(value = "execution(* com.zly.aop.annotation.CalculatorImpl.* (..))")public void pointCut() {}
}

[外链图片转存中...(img-o6Rg7hvZ-1677496876495)]

最后

希望各位大佬指正,点点👍

相关文章:

Spring之AOP理解及使用

文章目录AOP是什么AOPSpring的通知类型1.Before通知2. AfterReturning通知3.AfterThrowing通知4. After通知5. Around通知动态代理JDK动态代理CGLib动态代理动态代理的代码展示AOP使用切面类的配置最后大家好&#xff0c;我是Leo&#xff01;今天给大家带来的是关于Spring AOP的…...

微信小程序和webview使用postMessage交互

小程序和webview能交互&#xff0c;但是没有你想的那个完美小程序向webview传递参数只能使用url携带参数webview向小程序传递参数可以使用postMessage, 但是注意了&#xff0c;postMessage只会在特定的时机执行&#xff0c;请看官方文档由此可见&#xff0c;如果你想点击webvie…...

pytorch-自动求导机制,构建计算图进行反向传播,需要注意inplace操作导致的报错,梯度属性变化

PyTorch 作为一个深度学习平台&#xff0c;在深度学习任务中比 NumPy 这个科学计算库强在哪里呢&#xff1f;一是 PyTorch 提供了自动求导机制&#xff0c;二是对 GPU 的支持。由此可见&#xff0c;自动求导 (autograd) 是 PyTorch&#xff0c;乃至其他大部分深度学习框架中的重…...

【Project】项目管理软件学习笔记

一、前言使用Project制定项目计划步骤大致如下&#xff1a;以Project2013为例&#xff0c;按照上图步骤指定项目计划。二、实施2.1 创建空白项目点击文件——新建——空白项目&#xff0c;即完成了空白项目的创建&#xff0c;在此我把该项目保存为60mm项目管理.mpp&#xff0c;…...

【算法设计-分治思想】快速幂与龟速乘

文章目录1. 快速幂2. 龟速乘3. 快速幂取模4. 龟速乘取模5. 快速幂取模优化1. 快速幂 算法原理&#xff1a; 计算 311&#xff1a; 311 (35)2 x 335 (32)2 x 332 3 x 3仅需计算 3 次&#xff0c;而非 11 次 计算 310&#xff1a; 310 (35)235 (32)2 x 332 3 x 3仅需计算…...

Kafka(十一) 如何保证数据的不重复和不丢失

数据不丢失 1&#xff09;从生产端&#xff1a;acks -1&#xff0c;&#xff08;ack应答机制&#xff09;从生产端到节点端&#xff0c;当所有isr集合里的节点备份完毕后返回成功&#xff1b; 2&#xff09;从节点端&#xff1a;每个partition至少需要一个isr节点&#xff0…...

解决树莓派 bullseye (11) 系统无法通过 xrdp 远程连接的问题

我手上有一台树莓派 4B&#xff0c;使用官方镜像烧录器烧录老版本操作系统 buster (10) 时可以正常通过 Windows 远程桌面连接上&#xff0c;但换成最新的 bullseye (11) 系统后却无法正常连接远程桌面。 问题复现&#xff1a; 使用官方镜像烧录器烧录&#xff0c;配置用户名为…...

微信公众号历史作品定向采集

最近有遇到微信公众号历史作品采集的需求,这里做一下记录, 登录自己注册好的的微信公众号后台进入创作界面,点击右上角的引用: 弹出如下界面: 选择查找公众号文章,输入要查找的公众号: 回车: 同时就可以打开F12开始抓包,选择公众号点击进入: appmsg?action=li…...

Vue学习笔记(3)

3.1 计算属性和监视属性 3.1.1 计算属性 计算属性是一种计算值的方式&#xff0c;可以根据其他属性的值来动态地计算新的属性值。计算属性可以缓存计算结果&#xff0c;当依赖的属性发生改变时&#xff0c;才会重新计算。在Vue中&#xff0c;可以使用computed选项来定义计算属…...

Marshmallow 库

文章目录Marshmallow 库介绍使用序列化反序列化参数介绍schema参数fields 参数钩子函数内置验证器Meta 属性Marshmallow 库 介绍 marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库&#xff0c;简而言之&#xff0c;就是实现object -> dict&#…...

【BN层的作用】论文阅读 | How Does Batch Normalization Help Optimization?

前言&#xff1a;15年Google提出Batch Normalization&#xff0c;成为深度学习最成功的设计之一&#xff0c;18年MIT团队将原论文中提出的BN层的作用进行了一一反驳&#xff0c;重新揭示BN层的意义 2015年Google团队论文&#xff1a;【here】 2018年MIT团队论文&#xff1a;【h…...

re.sub()用法的详细介绍

一、前言 在字符串数据处理的过程中&#xff0c;正则表达式是我们经常使用到的&#xff0c;python中使用的则是re模块。下面会通过实际案例介绍 re.sub() 的详细用法&#xff0c;该函数主要用于替换字符串中的匹配项。 二、函数原型 首先从源代码来看一下该函数原型&#xf…...

【Python数据挖掘入门】2.2文本分析-中文分词(jieba库cut方法/自定义词典load_userdict/语料库分词)

中文分词就是将一个汉字序列切分成一个一个单独的词。例如&#xff1a; 另外还有停用词的概念&#xff0c;停用词是指在数据处理时&#xff0c;需要过滤掉的某些字或词。 一、jieba库 安装过程见&#xff1a;https://blog.csdn.net/momomuabc/article/details/128198306 ji…...

Meta利用视觉信息来优化3D音频模型,未来将用于AR/VR

我们知道&#xff0c;Meta为了给AR眼镜打造智能助手&#xff0c;专门开发了第一人称视觉模型和数据集。与此同时&#xff0c;该公司也在探索一种将视觉和语音融合的AI感知方案。相比于单纯的语音助手&#xff0c;同时结合视觉和声音数据来感知环境&#xff0c;可进一步增强智能…...

openlayers加载离线地图并实现深色地图

问题背景 我们自己一直使用的openlayergeoserver自己发布的地图&#xff0c;使用的是矢量地图。但是由于政府地图大都使用为天地图&#xff0c;所以需要将geoserver的矢量地图更改为天地图&#xff0c;并且依旧是搭配openlayers来使用。 解决步骤 一&#xff1a;加载离线地图&a…...

socket,tcp,http三者之间的区别和原理

目录 一、OSI模型也称七层网络模型 1、TCP/IP连接 1.1三次握手与四次挥手的简单理解&#xff1a;&#xff08;面试重点&#xff09; 1.2面试考题&#xff1a;如果已经建立了连接&#xff0c;但是客户端突然出现故障了怎么办&#xff1f; 1.3 socket、tcp、http三者之间有什…...

红日(vulnstack)1 内网渗透ATTCK实战

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;sx22 攻击机系统&#xff1a;kali linux 2022.03 网络配置&#xff1a; win7配置&#xff1a; kali配置&#xff1a; kali 192.168.1.108 192.168.111.129 桥接一块&#xff0c;自定义网卡4 win7 1…...

ik 分词器怎么调用缓存的词库

IK 分词器是一个基于 Java 实现的中文分词器&#xff0c;它支持在分词时调用缓存的词库。 要使用 IK 分词器调用缓存的词库&#xff0c;你需要完成以下步骤&#xff1a; 创建 IK 分词器实例 首先&#xff0c;你需要创建一个 IK 分词器的实例。可以通过以下代码创建一个 IK 分…...

ROS1/2机器人操作系统与时间Time的不解之缘

时间对于机器人操作系统非常重要。所有机器人类的编程中所涉及的变量如果需要在网络中传输都需要这个数据结构的时间戳。宏观上&#xff0c;ROS1、ROS2各版本都有官方支持的时间节点。ROS时钟--支持时间倒计时小工具效果如下&#xff1a;如果要部署机器人操作系统&#xff0c;R…...

华为OD机试真题2022(JAVA)

华为机试题库已换 →→→ 华为OD机试2023&#xff08;JAVA&#xff09; 以下题目为旧版题库&#xff0c;供大家课外消遣 基础题&#xff1a; 序号题目分值1查找众数及中位数1002出错的或电路1003连续字母长度1004分班1005计算面积1006最远足迹1007判断一组不等式是否满足约束…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...