Spring AOP (二)

本篇将介绍Spring AOP的相关原理。

一、代理模式

Spring 在实现AOP时使用了代理模式这种设计模式,什么是代理模式呢我们来了解一下。

代理模式可以理解为当我们需要调用某个类的方法时,在我们与这个目标类之间增加一个代理类,我们要使用目标类的方法时,通过代理类访间接访问,而不是直接访问,这个目标类的方法称之为被代理对象。

在我们生活中 ,其实很多地方都有使用代理模式的思想,例如当我们去租房子时,我们需要与房东去建立联系,但通常情况下我们并不会直接去联系房东,而是通过中介去联系房东。此时,我们就相当于调用方,而房东则是我们的被代理对象,而中介就是我们的代理类。

对于代理模式的实现,通常有两种方式,一种是动态代理,一种是静态代理。这两种代理的区别主要在于代理类的生成时间不同。静态代理的代理类在项目编译前就已经存在,而动态代理则是在项目运行期间根据被代理对象的情况动态生成代理类。下面我们通过实现前面租房子的场景具体了解一下这两种代理模式。

静态代理

在前面的租房子场景中,一共提到了三个角色租客(调用方)、中介(代理类)、房东(被代理类)。下面我们分别创建代码来代替这三个角色。

租客:

中介:

 

房东:

 

运行代码:

通过打印的日志可以发现,租客与房东之间都是通过中介来进行联系的,并且中介还可以在房东与租客之间新增一些处理逻辑。

上述这种静态代理的模式事实上存在很多缺陷,代理类是写死的,如果房东的业务做出了改变,我们还需要重新对代理类进行修改,例如我们房东需要新增一个出售门面的业务:

代理类中介也得跟者进行修改:
 这也就意味着每修改一次被代理对象,代理类都得重新进行调整,这样不仅麻烦,还会降低我们的开发效率。因此在Spring AOP中并没有使用这种静态代理的模式,而是另外一种动态代理的模式。

动态代理

在Spring AOP中对于动态代理的实现方式有两种,一种是JDK动态代理,另一种则是CGLIB动态代理。

JDK动态代理

jdk动态代理是一种基于反射创建代理类的动态代理方式,使用这种方式的步骤如下:

  1. 创建一个接口,并以该接口的实现类作为目标对象的类。
  2. 创建InvocationHandler接口的实现类,重写其中的invoke方法,并在这个方法中调用我们的目标方法并编写一些我们需要增强的功能
  3. 通过Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)方法基于反射创建代理类。其中loader为类加载器,interfaces为被代理类所实现的接口,h为我们在上一步创建的InvocationHandler的实现类。
  4. 当调用目标方法时,使用前面的代理类来调用。

下面我们根据这个步骤来对前面的静态代理的代码来改造一下。

改造结果如下:

InvocationHandler的实现类:

 创建目标方法所在类的接口,并让我们前面的房东类实现该接口:

 

 最后创建代理类并使用:

执行结果如下:

可以发现代理类的增强效果已经生效了,并且目标方法也顺利执行了。

在使用JDK动态代理时有一些注意点,第一,只能代理有实现接口的类中的方法,未实现接口的类中的方法无法通过使用这种动态代理方式。第二,只能代理接口中定义的方法,接口中没有的方法,无法被定义,例如我们再往房东(Landlord)类中再添加一个test方法

通过前面我们根据JDK动态代理创建的代理类是无法代理这个方法的,

至于为什么只能代理接口中的方法,原因其实也很容易猜出来,通过上面创建代理类的代码可以发现我们将代理类强转成了Seller类,由此可以推断出这个代理类其实是Seller接口的一个实现类,并重写了里面的方法,并在方法里通过反射获取到另一个实现类,也就是目标方法所在类里重写的方法,然后再执行增强的内容和这些方法(目标方法)。因此,可以总结一下JDK动态代理可以使用的场景:实现了某个接口,并且接口中有定义方法,这样的类才能使用JDK动态代理,并且只能代理接口中有所定义的方法。

CGLIB动态代理

CGLIB动态代理是一种基于ASM的字节码生产库,它是通过继承来实现动态代理的。使用CGLIB动态代的具体步骤如下:

  1. 引入CGLIB依赖
    <dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.3.0</version>
    </dependency>

  2. 创建被代理类,不再需要实现接口
  3. 创建MenthodIntercept的实现类,并通过intercept方法(和JDK动态代理中的invoke方法类似)来对目标方法进行增强
  4. 通过Enhancer的create(class type,Callbackcallback)创建代理类其中type为被代理类的类型,callback为上一步MenthodIntercept的实现类
  5. 使用代理类访问目标方法

接下来我们再将前面JDK版本的动态代理代码改为CGLIB动态代理的

创建MenthodInterCept的实现类:

创建代理类 修改房东类,不需要再实现接口:

使用CGLIB动态代理无需目标类实现接口,因此CGLIB对于绝大多数类都可以进行代理。

Spring AOP中对于动态代理的使用

在Spring AOP中对于CGLIB动态代理和JDK动态代理都进行了使用。具体使用哪种取决于配置项proxyTargetClass和目标类的情况,具体如下:

proxyTargetClass目标类是否实现接口使用动态代理的类型
trueCGLIB动态代理
true

CGLIB动态代理

falseJDK动态代理
trueCGLIB动态代理

对于Spring Boot 和Spring framework 来说proxyTargetClass的默认值略有不同,在Spring Boot

2.X版本以前,这个值默认和Spring framework一样设置为false,而在Spring Boot2.X版本以后,Spring Boot将proxyTargetClass的默认值改为了true。

在Spring Boot中我们也可以通过配置文件手动对proxyTargetClass进行修改,配置项为pring.aop.proxy-target-class=false,但需要注意的是并不是将proxyTargetClass设为false,对于实现了接口的目标类就一定使用JDK动态代理,还需要结合具体情况来看,如果实现的接口里没有定义方法,是不能使用JDK动态代理的,因此这种情况下还是得使用CGLIB动态代理。

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

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

相关文章

vue2响应式 VS vue3响应式

Vue2响应式 存在问题&#xff1a; 新增属性&#xff0c;删除属性&#xff0c;界面不会更新。 直接通过下标修改数组界面不会自动更新。 Vue2使用object.defineProperty来劫持数据是否发生改变&#xff0c;如下&#xff1a; 能监测到获取和修改属性&#xff1a; 新增的属性…

【C++打怪之路】-- C++开篇

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &…

【C语言】深入解析选择排序算法

一、算法原理二、算法性能分析三、C语言实现示例四、总结 一、算法原理 选择排序&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法。它的工作原理是不断地选择剩余元素中的最小&#xff08;或最大&#xff09;元素&#xff0c;放到已排序的序列的末尾&#xff…

securecrt 批量登录服务器介绍

一、前言 在有一些IT环境中&#xff0c;可能存在各种情况的服务器&#xff0c;因为各种原因不能统一部署类似ansible、saltstack等批量操控软件&#xff0c;当遇到需要对这些服务器进行某项信息的排查或调整配置时&#xff0c;你是否还是通过securecrt一台一台登录后进行操作&a…

endnote21从安装到使用!文献引用!Mac版

视频学习和资源获取 新建库 选择上方导航栏处的File下的New 软件 软件界面可以分成四个部分 2是个人图书馆 3是对某一分类中文献的展示 最右侧是对具体一篇文献的摘要、编辑以及PDF 有回形针标志意味着这篇有全文&#xff0c;也就是有pdf 如果没有回形针代表它只有引文信…

社交媒体数据恢复:BF Messager

BF Messenger 数据恢复方法 一、前言 BF Messenger&#xff08;BF加密聊天软件&#xff09;是一款基于布尔式循环移位加密算法的聊天应用程序。它使用对称密钥加密技术&#xff0c;用户可以在安全的环境下进行私密聊天。除此之外&#xff0c;该应用还具有防截屏、应用锁屏、密…

LeetCode in Python 55. Jump Game (跳跃游戏)

跳跃游戏的游戏规则比较简单&#xff0c;若单纯枚举所有的跳法以判断是否能到达最后一个下标需要的时间复杂度为O()&#xff0c;为此&#xff0c;本文采用贪心策略&#xff0c;从最后一个下标开始逆着向前走&#xff0c;若能跳到第一个元素则表明可以完成跳跃游戏&#xff0c;反…

本地主机搭建服务器后如何让外网访问?快解析内网端口映射

本地主机搭建应用、部署服务器后&#xff0c;在局域网内是可以直接通过计算机内网IP网络地址进行连接访问的&#xff0c;但在外网电脑和设备如何访问呢&#xff1f;由于内网环境下&#xff0c;无法提供公网IP使用&#xff0c;外网访问内网就需要一个内外网转换的介质。这里介绍…

stm32开发之netxduo组件之mqtt客户端的使用记录

前言 1使用mqtt协议的简单示例记录 代码 MQTT服务端(C# 编写,使用MQTTnet提供的示例代码) 主程序 namespace ConsoleApp1;public class Program {public static async Task Main(string[] args){await Run_Server_With_Logging();}}public static async Task Run_Server_Wi…

CERLAB无人机自主框架: 1-环境搭建

前言&#xff1a;更多更新文章详见我的个人博客主页【MGodmonkeyの世界】 描述&#xff1a;欢迎来到CERLAB无人机自主框架&#xff0c;这是一个用于自主无人飞行器 (UAV) 的多功能模块化框架。该框架包括不同的组件 (模拟器&#xff0c;感知&#xff0c;映射&#xff0c;规划和…

后台管理系统加水印(react)

效果 代码图片 代码 window.waterMark function (config) {var defaultConfig {content: 我是水印,fontSize: 16px,opacity: 0.3,rotate: -15,color: #ADADAD,modalId: J_waterMarkModalByXHMAndDHL,};config Object.assign({}, defaultConfig, config);var existMarkModal…

亚信安全入选中国数据安全市场图谱

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布了《IDC Market Glance&#xff1a;中国数据安全市场图谱&#xff0c;2024》报告&#xff08;以下简称“报告”&#xff09;&#xff0c;报告展示了中国数据安全市场的构成和格局&#xff0c;遴选出不同细分市场领域的主…

rabbitmq 使用SAC队列实现顺序消息

rabbitmq 使用SAC队列实现顺序消息 前提 SAC: single active consumer, 是指如果有多个实例&#xff0c;只允许其中一个实例消费&#xff0c;其他实例为空闲 目的 实现消息顺序消费&#xff0c;操作&#xff1a; 创建4个SAC队列,消息的路由key 取队列个数模&#xff0c;这…

java调用讯飞星火认知模型

前往讯飞开发平台选择产品&#xff0c;获取appId、apiKey、APISecret&#xff0c;这里我选择的是v3.0模型。 java后端实现 本项目以及实现了基本的会话功能&#xff0c;小伙伴可以自己扩充其他的例如绘画功能。 注意&#xff1a;星火模型的api使用的是websocket协议&#xf…

C++11(下篇)

文章目录 C111. 模版的可变参数1.1 模版参数包的使用 2. lambda表达式2.1 Lambda表达式语法捕获列表说明 2.2 lambda的底层 3. 包装器3.1 function包装器3.2 bind 4. 线程库4.1 thread类4.2 mutex类4.3 atomic类4.4 condition_variable类 C11 1. 模版的可变参数 C11支持模版的…

数据结构习题-- 相交链表

数据结构习题-- 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 如上图&#xff0c;返回c1结点 注意&#xff1a;这两个链表非环形 方法&#xff1a;集合 分析 由…

关于ERA5气压和温度垂直补偿公式的对比情况

1. 气压和温度垂直补偿对比 「谨代表给个人观点&#xff0c;杠精请自测&#xff0c;对对对&#xff0c;好好好&#xff0c;你说啥都对」。 使用2020-2022陆态网GNSS与探空站并址的48个站点实验&#xff0c;以探空站为真值&#xff0c;验证ERA5精度。怎么确定并址请看前面文章…

Django中的实时通信:WebSockets与异步视图的结合

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在现代Web应用程序中&#xff0c;实时通信已经成为了必不可少的功能之一。无论是在线聊天、…

UKP3D,出轴 /平面图时,选项中出图比例,绘图比例,打印比例的区别

Q:用户问&#xff0c;轴测图正常&#xff0c;平面图位置不对&#xff0c;这个也需要在xml里面调整吗&#xff1f; 在此&#xff0c;先不回复上述问题&#xff0c;而是解释在出图规则里的选项意思。 1.图框比例&#xff1a;图框比例1:100&#xff0c;例如选中的图幅是A0横式&…

现代图形API综合比较:Vulkan | DirectX | Metal | WebGPU

Vulkan、DirectX、Metal 和 WebGPU 等低级图形 API 正在融合为类似于当前 GPU 构建方式的模型。 图形处理单元 (GPU) 是异步计算单元&#xff0c;可以处理大量数据&#xff0c;例如复杂的网格几何形状、图像纹理、输出帧缓冲区、变换矩阵或你想要计算的任何数据。 NSDT工具推荐…