首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

反编译看JDK的动态代理原理

经常听到动态代理,总是觉得是很复杂的东西,今天通过设置特殊参数轻松理解动态代理。

代码实现

目标方法与代理类代码如下图:

这里为了展示把三个类放到一个文件中,首先是一个接口包含一个getName方法,然后是被代理类,它实现了这个接口。最后是动态代理对象,它实现了接口InvocationHandler并实现了一个invoke方法,invoke方法就是具体的代理方法。

运行测试代码如下图:

main方法的第一行设置了一个系统参数,这个在后面一点讲。

看后面的代码接下来创建了两个接口SubjectInterface、InvocationHandler的两个实现,通过接口处理两个模块的交互,这是程序设计中比较常见的方式。最关键在接下来一步,Proxy.newProxyInstance需要三个参数ClassLoader、interfaces、InvocationHandler 这样就创建出来一个对象,它可以被转换成SubjectInterface,转换成SubjectInterface执行getName,至此动态代理就实现完成。

通过打印结果可以看到确实是实现了动态代理,代码比较简单,代理类与被代理类比较独立,主要是通过Proxy.newProxyInstance方法关联起来。被代理类以后只要在接口中新增方法并实现,新的方法也就实现了代理。而代理类的改变并不需要修改被代理类。

动态代理实现比较简单,不过留有两个疑问:

1、为什么Proxy.newProxyInstance方法产生的对象可以被转换成SubjectInterface

2、转换对象执行getName方法为什么会实现代理类中的代码?

反编译解答疑问

我们在main方法的最后两行打印了proxySubject的类名以及父类名,可以看到他是是一个我们完全没有见过的类,这说明Proxy.newProxyInstance创建了一个新类,并创建了它的具体对象。

在main方法的第一行代码:

System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

就是把创建的这个类文件保存到本地,保存结果如下图:

可以看到创建的是一个class文件,通过idea可以看到反编译过来的代码,剩余代码如下图:

通过这个class文件我们就一个解释之前留下的两个疑问了。我们可以看到这个类继承了Proxy并且实现了SubjectInterface,这就解释了为什么可以被转换成SubjectInterface

至于为什么能够执行代理类的代码,我们看生成类的的getName()方法,真正的代码为super.h.invoke(this, m3, (Object[])null);super也就是Proxy,看下Proxy的h如下图:

所以h代表的就是InvocationHandler这个接口,而他的具体实现类是ProxyHandler,这样最终proxySubject.getName();执行的代码是ProxyHandler中的invoke方法。

总结

整理这几个类关系图如下图:

JDK的动态代理是通过Proxy.newProxyInstance方法创建了一个类,这个类继承Proxy,并且实现了在Proxy.newProxyInstance方法中设置的用户接口,这样这个类就可以执行接口的所有方法,而方法的具体实现则是指向父类ProxyProxyHandler的invoke方法,最终来实现代理。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200512A0QDDS00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券