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动态代理
基于接口的动态代理
-
对于JDK代理,目标类需要实现一个Interface
-
InvocationHandler是一个接口,可以实现这个接口,再通过调用反射机制(invoke)调用目标类的代码
-
Proxy可以使用newProxyInstance,传入类加载器,目标的接口,InvocationHandler,生成一个动态代理的对象
CGLib动态代理
基于类的动态代理
-
JDK代理的一大限制是只能为接口创建代理实例,CgLib没有这个限制
-
CgLib创建的动态代理对象性能比JDK性能要高
-
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() {}
}
最后
希望各位大佬指正,点点👍
相关文章:

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

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

pytorch-自动求导机制,构建计算图进行反向传播,需要注意inplace操作导致的报错,梯度属性变化
PyTorch 作为一个深度学习平台,在深度学习任务中比 NumPy 这个科学计算库强在哪里呢?一是 PyTorch 提供了自动求导机制,二是对 GPU 的支持。由此可见,自动求导 (autograd) 是 PyTorch,乃至其他大部分深度学习框架中的重…...

【Project】项目管理软件学习笔记
一、前言使用Project制定项目计划步骤大致如下:以Project2013为例,按照上图步骤指定项目计划。二、实施2.1 创建空白项目点击文件——新建——空白项目,即完成了空白项目的创建,在此我把该项目保存为60mm项目管理.mpp,…...
【算法设计-分治思想】快速幂与龟速乘
文章目录1. 快速幂2. 龟速乘3. 快速幂取模4. 龟速乘取模5. 快速幂取模优化1. 快速幂 算法原理: 计算 311: 311 (35)2 x 335 (32)2 x 332 3 x 3仅需计算 3 次,而非 11 次 计算 310: 310 (35)235 (32)2 x 332 3 x 3仅需计算…...
Kafka(十一) 如何保证数据的不重复和不丢失
数据不丢失 1)从生产端:acks -1,(ack应答机制)从生产端到节点端,当所有isr集合里的节点备份完毕后返回成功; 2)从节点端:每个partition至少需要一个isr节点࿰…...

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

微信公众号历史作品定向采集
最近有遇到微信公众号历史作品采集的需求,这里做一下记录, 登录自己注册好的的微信公众号后台进入创作界面,点击右上角的引用: 弹出如下界面: 选择查找公众号文章,输入要查找的公众号: 回车: 同时就可以打开F12开始抓包,选择公众号点击进入: appmsg?action=li…...
Vue学习笔记(3)
3.1 计算属性和监视属性 3.1.1 计算属性 计算属性是一种计算值的方式,可以根据其他属性的值来动态地计算新的属性值。计算属性可以缓存计算结果,当依赖的属性发生改变时,才会重新计算。在Vue中,可以使用computed选项来定义计算属…...
Marshmallow 库
文章目录Marshmallow 库介绍使用序列化反序列化参数介绍schema参数fields 参数钩子函数内置验证器Meta 属性Marshmallow 库 介绍 marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库,简而言之,就是实现object -> dict&#…...

【BN层的作用】论文阅读 | How Does Batch Normalization Help Optimization?
前言:15年Google提出Batch Normalization,成为深度学习最成功的设计之一,18年MIT团队将原论文中提出的BN层的作用进行了一一反驳,重新揭示BN层的意义 2015年Google团队论文:【here】 2018年MIT团队论文:【h…...
re.sub()用法的详细介绍
一、前言 在字符串数据处理的过程中,正则表达式是我们经常使用到的,python中使用的则是re模块。下面会通过实际案例介绍 re.sub() 的详细用法,该函数主要用于替换字符串中的匹配项。 二、函数原型 首先从源代码来看一下该函数原型…...

【Python数据挖掘入门】2.2文本分析-中文分词(jieba库cut方法/自定义词典load_userdict/语料库分词)
中文分词就是将一个汉字序列切分成一个一个单独的词。例如: 另外还有停用词的概念,停用词是指在数据处理时,需要过滤掉的某些字或词。 一、jieba库 安装过程见:https://blog.csdn.net/momomuabc/article/details/128198306 ji…...

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

openlayers加载离线地图并实现深色地图
问题背景 我们自己一直使用的openlayergeoserver自己发布的地图,使用的是矢量地图。但是由于政府地图大都使用为天地图,所以需要将geoserver的矢量地图更改为天地图,并且依旧是搭配openlayers来使用。 解决步骤 一:加载离线地图&a…...
socket,tcp,http三者之间的区别和原理
目录 一、OSI模型也称七层网络模型 1、TCP/IP连接 1.1三次握手与四次挥手的简单理解:(面试重点) 1.2面试考题:如果已经建立了连接,但是客户端突然出现故障了怎么办? 1.3 socket、tcp、http三者之间有什…...

红日(vulnstack)1 内网渗透ATTCK实战
环境准备 靶机链接:百度网盘 请输入提取码 提取码:sx22 攻击机系统:kali linux 2022.03 网络配置: win7配置: kali配置: kali 192.168.1.108 192.168.111.129 桥接一块,自定义网卡4 win7 1…...
ik 分词器怎么调用缓存的词库
IK 分词器是一个基于 Java 实现的中文分词器,它支持在分词时调用缓存的词库。 要使用 IK 分词器调用缓存的词库,你需要完成以下步骤: 创建 IK 分词器实例 首先,你需要创建一个 IK 分词器的实例。可以通过以下代码创建一个 IK 分…...

ROS1/2机器人操作系统与时间Time的不解之缘
时间对于机器人操作系统非常重要。所有机器人类的编程中所涉及的变量如果需要在网络中传输都需要这个数据结构的时间戳。宏观上,ROS1、ROS2各版本都有官方支持的时间节点。ROS时钟--支持时间倒计时小工具效果如下:如果要部署机器人操作系统,R…...
华为OD机试真题2022(JAVA)
华为机试题库已换 →→→ 华为OD机试2023(JAVA) 以下题目为旧版题库,供大家课外消遣 基础题: 序号题目分值1查找众数及中位数1002出错的或电路1003连续字母长度1004分班1005计算面积1006最远足迹1007判断一组不等式是否满足约束…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...