最新要闻
- 韩国面板巨头要卖掉中国LCD工厂?TCL否认接盘:消息不实
- 女子拒绝调岗降薪被辞退:离职证明上写着“简历造假” 当事人难就业
- 世界速递!一加Ace 2新增18GB内存 被指反向升级 高管解释:真没有
- 【世界新视野】国内5月上映 迪士尼《小美人鱼》新剧照公布:脏辫黑人鱼与王子对视
- 天天速看:首发1350元 铭凡UM560XT迷你主机上架:锐龙5 5600H、液金散热
- 【聚看点】非法捕捞水产品案进行生态补偿 三亚海警局组织增殖放流3000尾鱼苗
- 24层楼高!我国首艘大型邮轮将交付:2500万个零件
- 【天天聚看点】文案没能逃过因AI失业!蓝色光标回应AI取代文案外包:属实
- 全球最资讯丨车主曝极氪001自动加速撞车:官方承认失控、但不担责任
- 《生化危机:死亡岛》角色介绍:克莱尔、瑞贝卡、吉尔太美了
- 播报:腾讯QQ邮箱关联邮箱帐号功能要没了!5月15日终止服务
- 王一鸣:重点激活服务消费,放松中高端商品和服务消费的限制性措施
- 当前热文:《CS:GO》价值百万库存玩家被封:只因给其他玩家留言
- 环球速读:华为智慧屏S3 Pro官宣:顶部配“AI慧眼”、超窄四边
- 比亚迪微型电动车海鸥内饰发布:看齐海豚、卖8万买不
- 环球快讯:豆瓣评分跌至6.4!成龙《龙马精神》票房艰难破亿
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
每日视讯:JdkProxy的进阶知识
如果想增强一个方法的功能,无非就是直接在方法体内直接修改。但这也无非给一些有代码洁癖人士一丝丝不悦!于是乎我们即不想在原来的代码里修改,又不想把原有的代码重新写一次,那么前辈们就发明了代理.注意:本文以 JdkProxy 为基础展开所有描述!
参与对象
那么一个代理过程参与的对象有以下几项:
(资料图片)
- 目标接口
- 目标类(Target)
- 代理基类(Proxy)
- 生成的代理类
- 调用处理程序(InvocationHandler)
目标接口。
至于为什么要用接口,这是JdkProxy的理论知识。文章结束后你也会明白!
public interface Fight { /** * 射击 */ void shot(); /** * 炸弹 */ void bomb();}
目标类
就是需要被代理的类!
public class BeautifulCountryTarget implements Fight { private static final Logger LOGGER = LoggerFactory.getLogger(BeautifulCountryTarget.class); /** * 射击 */ @Override public void shot() { LOGGER.debug("M4 shot ---> big goose!"); } /** * 炸弹 */ @Override public void bomb() { LOGGER.debug("HIMARS fire ---> big goose!"); }}
调试和输出结果
public class JdkProxy { private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class); /** * 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意 * * 1:生成的 代理对象 是实现了 目标接口 * 2:生成的 代理对象 与 代理目标 是兄弟关系 (都实现了同一个目标接口) * */ public static void main(String[] args) throws InterruptedException { // jdkProxy jdkProxyTest(); } public static void jdkProxyTest() throws InterruptedException { //类加载器,负责把生成的class($Proxy???)文件加载到JVM ClassLoader loader = JdkProxy.class.getClassLoader(); //需要代理的目标(对象) BeautifulCountryTarget target = new BeautifulCountryTarget(); //增强目标方法的处理程序 InvocationHandler handler = (proxy, method, args) -> { LOGGER.debug("大哥你在旁边看着喝Coffee!,武器开给,我来打!"); //方法调用,(目标对象,参数) return method.invoke(target, args); }; //创建代理人 Fight w_k_l_Fight = (Fight)Proxy.newProxyInstance( loader, new Class[]{Fight.class}, handler ); //打印下类路径,方便使用 arthas 进行反张译 LOGGER.debug("proxy class {}", w_k_l_Fight.getClass()); //代理人调用方法 w_k_l_Fight.shot(); w_k_l_Fight.bomb(); }}
打印出
19:22:41.839 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- proxy class class jdk.proxy1.$Proxy019:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- M4 shot ---> big goose!19:22:41.842 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!19:22:41.842 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- HIMARS fire ---> big goose!
可以看出代理生效了,-_-!
那么通过 Proxy.create函数生成的是一字节码文件(至于怎么生成,太高端没去研究),它被 loader 加载到JVM,通过 debug只看了类名$Proxy0
模拟手写代理类
既然是系统自己生成的,那么我们自己可以自己写一个,不用系统生成的~。由理论知识可以写出以下 代理类
/** * 模拟 通过 Proxy.create 出来的 $Proxy?? 类, * */public class SimulateProxy extends Proxy implements Fight { protected SimulateProxy(InvocationHandler h) { super(h); } /** * 射击 */ @Override public void shot() { try { // 代理的方法 Method pMethod = Fight.class.getMethod("shot"); //调用增强处理器 super.h.invoke(this, pMethod, null); } catch (Throwable e) { e.printStackTrace(); } } /** * 炸弹 */ @Override public void bomb() { try { // 代理的方法 Method pMethod = Fight.class.getMethod("bomb"); //调用增强处理器 super.h.invoke(this, pMethod, null); } catch (Throwable e) { e.printStackTrace(); } }}
调试输出
public class JdkProxy { private static final Logger LOGGER = LoggerFactory.getLogger(JdkProxy.class); /** * 通过 Proxy.create 生成的对象是代理对象,基于 接口的代理对象,那么有以下几点是需要注意 * * 1:生成的 代理对象 是实现了 目标接口 * 2:生成的 代理对象 与 代理目标 是兄弟关系 (都实现了同一个目标接口) * */ public static void main(String[] args) throws InterruptedException { // 模拟代理类 simulateProxyTest(); } public static void simulateProxyTest() { //需要代理的目标(对象) BeautifulCountryTarget target = new BeautifulCountryTarget(); //增强目标方法的函数 InvocationHandler handler = (proxy, method, args) -> { LOGGER.debug("大哥你在旁边看着喝Coffee!,武器开给,我来打!"); return method.invoke(target, args); }; //创建代理人 这里换成自己手写的 Fight w_k_l_Fight = new SimulateProxy(handler); //代理人调用方法 w_k_l_Fight.shot(); w_k_l_Fight.bomb(); }}
同样输出
19:38:23.950 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!19:38:23.951 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- M4 shot ---> big goose!19:38:23.951 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- 大哥你在旁边看着喝Coffee!,武器开给,我来打!19:38:23.951 [main] DEBUG com.java.coffeetime.aop.BeautifulCountryTarget -- HIMARS fire ---> big goose!
总结
我们先来看下系统生成的$Proxy0
是什么样。现在通过在main
方法添加 System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
可以把系统生成的代理class文件写到目录里root/jdk/proxy1/$Proxy0.class
。我这里直接贴出来,方便和上下文对比。
public final class $Proxy0 extends Proxy implements Fight { private static final Method m0; private static final Method m1; private static final Method m2; private static final Method m3; private static final Method m4; public $Proxy0(InvocationHandler param1) { super(var1); } public final int hashCode() { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final boolean equals(Object var1) { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void shot() { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void bomb() { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m0 = Class.forName("java.lang.Object").getMethod("hashCode"); m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.java.coffeetime.aop.Fight").getMethod("shot"); m4 = Class.forName("com.java.coffeetime.aop.Fight").getMethod("bomb"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } private static Lookup proxyClassLookup(Lookup var0) throws IllegalAccessException { if (var0.lookupClass() == Proxy.class && var0.hasFullPrivilegeAccess()) { return MethodHandles.lookup(); } else { throw new IllegalAccessException(var0.toString()); } }}
那么对比下系统生成的和自己手写的代理类区别 SimulateProxy和 $Proxy0,可以看出系统生成的代理类比我们手写的比较优雅一些!
- 利用静态方法把需要代理的目标方法在加载阶段就初始化了,而不需要每次调用的时候去通过反射获取到.
- 多了
equals
,toString
,hashCode
,有意思的是代理类和目标类 equals是 ture, 但是不同的实例!19:49:59.622 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- w_k_l_Fight equals target ? true19:49:59.622 [main] DEBUG com.java.coffeetime.aop.JdkProxy -- w_k_l_Fight == target ? false
- 通过生成的代理类可以看出,的确是实现了 目标接口(和目标类一样),和代理类是兄弟关系,但又胜似兄弟!
- 对异常的处理
本文示例代码
关键词:
每日视讯:JdkProxy的进阶知识
全球快看点丨【Visual Leak Detector】Release 模式下使用 VLD
【环球聚看点】债市日报:4月12日
韩国面板巨头要卖掉中国LCD工厂?TCL否认接盘:消息不实
女子拒绝调岗降薪被辞退:离职证明上写着“简历造假” 当事人难就业
世界速递!一加Ace 2新增18GB内存 被指反向升级 高管解释:真没有
【世界新视野】国内5月上映 迪士尼《小美人鱼》新剧照公布:脏辫黑人鱼与王子对视
天天速看:首发1350元 铭凡UM560XT迷你主机上架:锐龙5 5600H、液金散热
【聚看点】非法捕捞水产品案进行生态补偿 三亚海警局组织增殖放流3000尾鱼苗
全球即时:最全的python正则使用
环球精选![翻译]ExecutionContext vs SynchronizationContext
24层楼高!我国首艘大型邮轮将交付:2500万个零件
【天天聚看点】文案没能逃过因AI失业!蓝色光标回应AI取代文案外包:属实
全球最资讯丨车主曝极氪001自动加速撞车:官方承认失控、但不担责任
《生化危机:死亡岛》角色介绍:克莱尔、瑞贝卡、吉尔太美了
播报:腾讯QQ邮箱关联邮箱帐号功能要没了!5月15日终止服务
王一鸣:重点激活服务消费,放松中高端商品和服务消费的限制性措施
天天最新:新人必看| 移动端“动态化”是什么意思?
guacamole免密登录,guacamole不通过登录界面登录,guacamole指定用户名免密登录
天天快看点丨图数据库驱动的基础设施运维实操
java 如何计算两个汉字的相似度?如何获得一个汉字的相似汉字?
全球讯息:PostgreSQL 备忘清单_开发速查表分享
当前热文:《CS:GO》价值百万库存玩家被封:只因给其他玩家留言
环球速读:华为智慧屏S3 Pro官宣:顶部配“AI慧眼”、超窄四边
比亚迪微型电动车海鸥内饰发布:看齐海豚、卖8万买不
环球快讯:豆瓣评分跌至6.4!成龙《龙马精神》票房艰难破亿
每日速讯:“小Mate 50 Pro”实锤!华为畅享60X正面揭晓:旗舰同款刘海屏
环球今头条!4月15日 厦门邮轮母港公交场站正式启用(附公交调整方案)
环球消息!2023 年十大 API 管理趋势
新资讯:如何打开 plist 文件
每日短讯:Three.js教程:第一个3D场景
【天天时快讯】pymysql操作数据库入门
快看点丨高数上复习
辽宁发行150亿元专项债补充盛京银行资本金
【环球聚看点】《信托大家谈——信托业转型发展对大众意味着什么》
观点数字化大会 | 德信集团胡一平:一定要积极拥抱数字化改革
世界关注:非会员看剧遇3000多秒广告 优酷回应:确实会有 属极个别情况
世界今日讯!小米长焦之王!13 Ultra塞进两颗长焦镜头
专家称北京打车太便宜应涨价 崔东树曾任汽车销售
环球快看:女子疯狂网上购物确诊帕金森:过度伤害性冲动行为
世界最资讯丨自研大模型图片生成被质疑 商汤回应:秒画也有第三方开源模型
关于数智融合,看看这20位专家都聊了什么
热文:在.NET Core使用 HttpClient 的正确方式
看!前端新人如何用ChatGPT开发APP
JMeter-BeanShell预处理程序和BeanShell后置处理程序的应用
当前速读:智能指针基本原理,简单实现,常见问题
今日热门!叶一茜当众骂森碟“心机”,她就这么恨女儿?
【新华500】新华500指数(989001)12日窄幅震荡跌0.10%
沙尘跨过长江一路向南!直击江皖沪多地沙尘现场
要闻:GT Neo5 SE 1TB版只卖2599 真我喊话:现货才是硬道理
RTX 4070今晚发布 结果遭AMD背刺了:显存越大越好、4K至少16GB
全球头条:史上最挤”五一档来了!王一博《长空之王》等17部影片扎堆上映
网传明年中旬上海绿牌蓝牌要合并?官方回应来了
当前速读:梯田为“布” 光影为“沙” 点亮乡村“夜经济”
世界热消息:C#使用Elasticsearch入门
plist文件格式转换器
观速讯丨T-SQL基础教程Day1
天天微头条丨云图说|云数据库GaussDB如何做到卓越性能
环球最资讯丨不怕有味儿 比毛巾划算:云南白药洗脸巾0.06元/张狂促
天天热点评!“回锅沙”要来了!部分地方要注意
全球短讯!果粉最期待的大屏MacBook Air来了!苹果史上第一款
世界视点!首款骁龙8+平板中兴Axon Pad来了:12.1寸超大屏
新动态:4月14日State of Play:将展示超20分钟《最终幻想16》
全球看热讯:电商平台商品详情接口的应用场景
热点!二级指针创建二叉树节点与一级指针创建二叉树节点
身体很诚实!马斯克加入AIGC大战:抢购1万张GPU、挖Deepmind墙角
当前视讯!曾被誉为最靠谱!又一家造车新势力发不出工资了
全球微速讯:火山引擎 DataLeap 推出全链路智能监控报警平台
有病了还能买哪种保险?隐瞒健康告知带病投保会怎么样?
理想汽车全系车型电器真实功率再公开:空调果然是耗电大户!
小米13 Ultra样张首亮相:虚化堪比单反 夜拍效果惊人
《龙之家族》新季开拍
罕见超级激励!东方甄选奖励154员工8.83亿港元
【世界独家】00后网红骑摩托车遇车祸身亡 劝不住:网友感慨年轻 有必要全面禁摩?
易基因:METTL3介导的m6A甲基化谱调控肌肉干细胞成肌细胞状态转换|发育分化
全球快资讯丨中骏集团称已备好即将到期美元债兑付资金 拟发行第二支中债增全额担保中票
3月物价数据透露哪些经济变化?促消费政策获得较大空间
天天报道:iPhone 15 Pro颠覆式设计取消了!郭明錤:苹果因技术问题放弃固态按键
丫丫将通过温控卡车运至机场:即将飞赴上海
又有新品牌了!长安启源A07亮相:颜值超高碾压一众国产
报道:推特突然“死亡”!马斯克正式启动打造美版微信
走过别错过!红蜻蜓126款休闲鞋/运动鞋/皮鞋清仓:79元绝世好价
h3c路由器如何恢复出厂设置?h3c路由器配置命令大全
小米手机卡顿反应慢是什么原因?小米手机卡顿反应慢怎么解决?
ssd极速固态硬盘怎么样?ssd极速固态硬盘排名前十
iphone4的显示屏分辨率是多少?iphone4版本太低怎么下载软件?
AMD速龙QL64CPU性能怎么样?amd速龙系列cpu天梯图
Zabbix“专家坐诊”第187期问答汇总
每日报道:数据开发提效有秘诀!离线开发BatchWorks 六大典型场景拆解
全球观天下!公司入职一个阿里大佬,把 Spring Boot 系统启动时间从 7 分钟降到了 40 秒!
HTML中的pre-load 和 pre-fetch
全球最资讯丨京准GPS北斗卫星网络授时服务器助力高速智慧交通
环球观热点:三月三拜轩辕 | 全球华人同根同源——强月新
世界今亮点!雷军:小米13 Ultra将摆脱手机成片的“塑料味”
头条:淄博老板娘为赶高铁小伙1V1烤串!完美诠释“好客山东”
天天观察:苹果智能戒指专利首曝:VR场景交互只需动下手指
当前速读:1TB仅529元!致态TiPlus 7100固态硬盘新史低 选它还是选三星?
全球视讯!机构一致唱多金价 贵金属板块表现亮眼
世界热议:全网最详细中英文ChatGPT-GPT-4示例文档-场景问题智能生成从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js/
世界速讯:记一次kvm虚机mysql数据库磁盘扩容操作步骤及其问题小坑