浅谈动态代理

什么是动态代理?
以下为个人理解:
动态代理就是在程序运行的期间,动态地针对对象的方法进行增强操作。并且这个动作的执行者已经不是"this"对象了,而是我们创建的代理对象,这个代理对象就是类似中间人的角色,帮助我们为目标方法嵌入一些其他的逻辑进去。
jdk动态代理的原理
jdk自带的动态代理的工作原理是利用反射的newInstance,创建一个代理对象(proxy),获取到目标接口的方法,然后我们就可以在Invoke之前或之后做操作。它抽取出了一个invokeHandler,里面就有目标method。
试想一下,当我们拥有了class对象,增强逻辑(invokeHandler),也就是增强的目标方法之后,我们自己利用反射(不利用Proxy)也可以很容易写出我们自己的动态代理。但是问题就在于,我们只有明确了目标类之后,通过自己编写Proxy类,实现目标接口,往里面塞invoktionHandler, 最后New出来这个实实在在的对象。而jdk提供的动态代理,却可以在并不知情的情况下,帮我们做这一系列的动作。
jdk生成代理类时,并没有经历源码阶段,编译阶段,而是直接到字节码阶段,它生成的代理类是看不到的,因为它直接就是字节码文件了。 它帮我们继承了Proxy类,并且还动态的帮助我们继承了目标接口。也就是说,它帮我们写代码了。里面用到的技术,是ASM技术,它可以直接生成我们想要的字节码。
jdk方法反射调用优化:
invoke() 利用反射进行本地调用,效率低下,它在调用了一定的次数(16)之后会生成实例化对象,变成正常调用。
InvocationHandler接口
publicinterfaceInvocationHandler {
publicObjectinvoke(Objectproxy, Methodmethod, Object[] args)throwsThrowable;
}
源码
@CallerSensitive
publicstaticObjectnewProxyInstance(ClassLoaderloader,
Class<?>[] interfaces,
InvocationHandlerh)
throwsIllegalArgumentException
{
Objects.requireNonNull(h);
finalClass<?>[] intfs=interfaces.clone();
finalSecurityManagersm=System.getSecurityManager();
if (sm!=null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?>cl=getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm!=null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
finalConstructor<?>cons=cl.getConstructor(constructorParams);
finalInvocationHandlerih=h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(newPrivilegedAction<Void>() {
publicVoidrun() {
cons.setAccessible(true);
returnnull;
}
});
}
returncons.newInstance(newObject[]{h});
} catch (IllegalAccessException|InstantiationExceptione) {
thrownewInternalError(e.toString(), e);
} catch (InvocationTargetExceptione) {
Throwablet=e.getCause();
if (tinstanceofRuntimeException) {
throw (RuntimeException) t;
} else {
thrownewInternalError(t.toString(), t);
}
} catch (NoSuchMethodExceptione) {
thrownewInternalError(e.toString(), e);
}
}
cglib动态代理的原理
cglib动态代理的原理跟jdk的类似,只不过它是基于父类继承,也就是不需要实现接口就可以做增强。它的内部并不是InvoktionHandler,而是方法拦截器 MethodInterceptor 。
前面的jdk动态代理,它是利用ASM技术帮我们动态编写了一个proxy对象,其中继承了Proxy父类,实现了目标接口,而cglib则是利用ASM直接帮助我们继承了目标类,不需要接口。
并且有所区别的是,它不仅仅通过反射拿到method,还拿到了MethodProxy。
MethodInterceptor接口 继承了Callback接口,它的拦截方法里面有一个特殊的参数 MethodProxy,这玩意可以不通过反射调用方法,通过invokeSuper() 方法可以直接正常调用。
MethodProxy是怎么做到正常调用的?
其实就是我们前面提到的,继承了Proxy父类之后,就得到了父类的原始方法,当我调用invokeSuper的时候,直接调用的就是父类的原始方法。
MethodInterceptor
publicinterfaceMethodInterceptorextendsCallback {
Objectintercept(Objectvar1, Methodvar2, Object[] var3, MethodProxyvar4) throwsThrowable;
}
MethodProxy
invoke() 无反射调用
invokeSuper() 无反射调用
publicObjectinvoke(Objectobj, Object[] args) throwsThrowable {
try {
this.init();
MethodProxy.FastClassInfofci=this.fastClassInfo;
returnfci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetExceptionvar4) {
throwvar4.getTargetException();
} catch (IllegalArgumentExceptionvar5) {
if (this.fastClassInfo.i1<0) {
thrownewIllegalArgumentException("Protected method: "+this.sig1);
} else {
throwvar5;
}
}
}
publicObjectinvokeSuper(Objectobj, Object[] args) throwsThrowable {
try {
this.init();
MethodProxy.FastClassInfofci=this.fastClassInfo;
returnfci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetExceptionvar4) {
throwvar4.getTargetException();
}
}
相关文章:
浅谈动态代理
什么是动态代理?以下为个人理解:动态代理就是在程序运行的期间,动态地针对对象的方法进行增强操作。并且这个动作的执行者已经不是"this"对象了,而是我们创建的代理对象,这个代理对象就是类似中间人的角色,帮…...
Idea超好用的管理工具ToolBox(附带idea工具)
文章目录为什么要用ToolBox总结idea管理安装、更新、卸载寻找ide配置、根路径idea使用准备工作配置为什么要用ToolBox 快速轻松地更新,轻松管理您的 JetBrains 工具 安装自动更新同时更新插件和 IDE回滚和降级通过下载补丁或一组补丁而不是整个包,节省维护 IDE 的…...
Spring 中 ApplicationContext 和 BeanFactory 的区别
文章目录类图包目录不同国际化强大的事件机制(Event)底层资源的访问延迟加载常用容器类图 包目录不同 spring-beans.jar 中 org.springframework.beans.factory.BeanFactoryspring-context.jar 中 org.springframework.context.ApplicationContext 国际…...
情人节有哪些数码好物值得送礼?情人节实用性强的数码好物推荐
转瞬间,情人节快到了,大家还在为送什么礼物而烦恼?在这个以科技为主的时代,人们正在享受着科技带来的便利,其中,数码产品也成为了日常生活中必不可少的存在。接下来,我来给大家推荐几款比较实用…...
java中flatMap用法
java中map是把集合每个元素重新映射,元素个数不变,但是元素值发生了变化。而flatMap从字面上来说是压平这个映射,实际作用就是将每个元素进行一个一对多的拆分,细分成更小的单元,返回一个新的Stream流,新的…...
【MySQL Shell】8.9.2 InnoDB ClusterSet 集群中的不一致事务集(GTID集)
AdminAPI 的 clusterSet.status() 命令警告您,如果 InnoDB 集群的 GTID 集与 InnoDB ClusterSet 中主集群上的 GTID 集不一致。与 InnoDB ClusterSet 中的其他集群相比,处于此状态的集群具有额外的事务,并且具有全局状态 OK_NOT_CONSISTENT 。…...
logstash毫秒时间戳转日期以及使用业务日志时间戳替换原始@timestamp
文章目录问题解决方式参考问题 在使用Kibana观察日志排查问题时发现存在很多组的timestamp 数据一样,如下所示 详细观察内部数据发现其中日志数据有一个timestamp字段保存的是业务日志的毫秒级时间戳,经过和timestamp数据对比发现二者的时间不匹配。经…...
【C语言】qsort——回调函数
目录 1.回调函数 2.qsort函数 //整形数组排序 //结构体排序 3.模拟实现qsort //整型数组排序 //结构体排序 1.回调函数 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来…...
8年软件测试工程师经验感悟
不知不觉在软件测试行业,野蛮生长了8年之久。这一路上拥有了非常多的感受。有迷茫,有踩过坑,有付出有收获, 有坚持! 我一直都在软件测试行业奋战, 毕业时一起入职的好友已经公司内部转岗,去选择…...
腾讯云安全组配置参考版
官方文档参考: 云服务器 安全组应用案例-操作指南-文档中心-腾讯云 新建安全组时,您可以选择腾讯云为您提供的两种安全组模板: 放通全部端口模板:将会放通所有出入站流量。放通常用端口模板:将会放通 TCP 22端口(Lin…...
代码覆盖率工具OpenCppCoverage在Windows上的使用
OpenCppCoverage是用在Windows C上的开源的代码覆盖率工具,源码地址为https://github.com/OpenCppCoverage/OpenCppCoverage ,最新发布版本为0.9.9.0,License为GPL-3.0。 从https://github.com/OpenCppCoverage/OpenCppCoverage/releases 下载…...
代码随想录算法训练营第24天25天|● 77. 组合● 216.组合总和III ● 17.电话号码的字母组合
77组合 看完题后的思路 void f(数组,startIndex)递归终止 if(startIndex数组长度||path.sizek){ if(path.sizek){ 加入} }递归 for(;startIndex<num.size;startIndex࿰…...
Python_pytorch
python_pytorch 小土堆pytotch学习视频链接 from的是一个个的包(package) import 的是一个个的py文件(file.py) 所使用的一般是文件中的类(.class) 第一步实例化所使用的类,然后调用类中的方法(def) Dataset 数据集处理 import os from PIL impo…...
【Java|golang】2335. 装满杯子需要的最短总时长
现有一台饮水机,可以制备冷水、温水和热水。每秒钟,可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。 给你一个下标从 0 开始、长度为 3 的整数数组 amount ,其中 amount[0]、amount[1] 和 amount[2] 分别表示需要装满冷水、温水和热水的…...
shell编程之sed
文章目录八、shell编程之sed8.1 工作原理8.2 sed基本语法8.3 模式空间中的编辑操作8.3.1 地址定界8.3.2 常用编辑命令8.4 sed扩展八、shell编程之sed 8.1 工作原理 sed是一种流编辑器,它是文本处理中非常有用的工具,能够完美的配合正则表达式使用&…...
安全寒假作业nginx反向代理+负载均衡上传webshell重难点+apache漏洞
1.应用场景 负载均衡作为现今解决web应用承载大流量访问问题的一种方案,在真实环境中得到广泛的部署。实现负载均衡的方式有很多种,比如 DNS 方式、HTTP 重定向方式、IP 负载均衡方式、反向代理方式等等。 比如基于dns的负载均衡: 当然还有…...
day35|01背包问题、416. 分割等和子集
01背包问题 有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 例:背包最大重量为4。 物品为: 重量价值物品0115物品…...
Linux内核启动(3,0.11版本)内核启动完成与进入内核main函数
这一部分是在讲解head.s代码,这个代码与bootsect.s和setup.s在同一目录下,但是head.s程序在被编译生成目标文件后会与内核其他程序一起被链接成system模块,位于system模块的最前面开始部分。system模块将被放置在磁盘上setup模块之后开始的扇…...
【2023】Prometheus-Alertmanager高可用集群
本次实验准备了三个节点,分别为laert-01~03 目录1.安装Alertmanager2.配置启动文件3.验证集群4.关于集群的配置项1.安装Alertmanager 这部分内容在三个节点上都要执行 下载安装包,将安装包解压至/data目录下 wget https://github.com/prometheus/aler…...
2023-2-11 刷题情况
最短路计数 题目描述 给出一个 NNN 个顶点 MMM 条边的无向无权图,顶点编号为 1∼N1\sim N1∼N。问从顶点 111 开始,到其他每个点的最短路有几条。 输入格式 第一行包含 222 个正整数 N,MN,MN,M,为图的顶点数与边数。 接下来 MMM 行&…...
若依框架单点登录!!!
一、不分离版在application.yml设置maxSession为1即可。修改shiro的配置shiro:session:# 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制)maxSession: 1# 踢出之前登录的/之后登录的用户,默认…...
Dlib零基础避坑指南:Windows Python环境一键部署实战
Dlib零基础避坑指南:Windows Python环境一键部署实战 【免费下载链接】Dlib_Windows_Python3.x Dlib compiled binary (.whl) for Python 3.7-3.11 and Windows x64 项目地址: https://gitcode.com/gh_mirrors/dl/Dlib_Windows_Python3.x 副标题:…...
如何快速掌握Windows系统权限管理:NSudo终极指南
如何快速掌握Windows系统权限管理:NSudo终极指南 【免费下载链接】NSudo [Deprecated, work in progress alternative: https://github.com/M2Team/NanaRun] Series of System Administration Tools 项目地址: https://gitcode.com/gh_mirrors/ns/NSudo 想要…...
Python 装饰器实战:用@syntax 优雅地增强函数功能
# Python 装饰器实战:用syntax 优雅地增强函数功能## 什么是装饰器?装饰器(Decorator)是 Python 中的一种高级特性,它允许你在不修改原函数代码的情况下,动态地给函数添加功能。简单来说,装饰器…...
二相四线步进电机驱动全解析:从原理到Proteus仿真避坑指南
二相四线步进电机驱动全解析:从原理到Proteus仿真避坑指南 在工业自动化与嵌入式开发领域,步进电机因其精准的位置控制能力成为不可或缺的执行元件。而二相四线制步进电机凭借结构简单、成本低廉的优势,尤其受到电子工程师和创客群体的青睐。…...
3步打造开源工具效率引擎:QtScrcpy自定义配置全指南
3步打造开源工具效率引擎:QtScrcpy自定义配置全指南 【免费下载链接】QtScrcpy Android实时投屏软件,此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限 项目地址: https://gitcode.com/barry-ran/QtScrcpy …...
Revit插件开发效率革命:热重载技术如何彻底改变你的开发流程
Revit插件开发效率革命:热重载技术如何彻底改变你的开发流程 【免费下载链接】RevitAddInManager Revit AddinManager update .NET assemblies without restart Revit for developer. 项目地址: https://gitcode.com/gh_mirrors/re/RevitAddInManager RevitA…...
Python从入门到精通(第08章):列表、元组、集合与字典
Python从入门到精通(第08章):列表、元组、集合与字典 开头导语 这是本系列第08章。本文采用"知识点讲解 + 错误示例 + 正确写法 + 自测清单"的结构,目标是让你不仅能看懂,还能独立写出可运行代码。建议你边看边敲,所有示例都亲自执行一次。 章节摘要 本章围…...
Beyond Compare 5密钥生成器:专业文件对比工具的永久激活方案
Beyond Compare 5密钥生成器:专业文件对比工具的永久激活方案 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否正在为Beyond Compare 5的30天评估期到期而烦恼?这款…...
MySQL登录报错1045?手把手教你找回丢失的root用户(附完整修复流程)
MySQL登录报错1045:从root用户丢失到完整恢复的实战指南 当你信心满满地输入mysql -u root -p准备开始一天的工作,却迎面撞上冰冷的"ERROR 1045 (28000): Access denied for user rootlocalhost"时,这种挫败感每个DBA都深有体会。更…...
