「阿里巴巴」反编译看JDK的动态代理原理


「阿里巴巴」反编译看JDK的动态代理原理
文章图片
「阿里巴巴」反编译看JDK的动态代理原理
文章图片
「阿里巴巴」反编译看JDK的动态代理原理
文章图片
「阿里巴巴」反编译看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\");
就是把创建的这个类文件保存到本地 , 保存结果如下图:
\t可以看到创建的是一个class文件 , 通过idea可以看到反编译过来的代码 , 剩余代码如下图:
\t通过这个class文件我们就一个解释之前留下的两个疑问了 。 我们可以看到这个类继承了 Proxy并且实现了SubjectInterface , 这就解释了为什么可以被转换成SubjectInterface 。
至于为什么能够执行代理类的代码 , 我们看生成类的的getName()方法 , 真正的代码为super.h.invoke(this m3 (Object[
)null);super也就是Proxy , 看下Proxy的h如下图:
\t所以h代表的就是InvocationHandler这个接口 , 而他的具体实现类是ProxyHandler , 这样最终proxySubject.getName();执行的代码是ProxyHandler中的invoke方法 。
总结整理这几个类关系图如下图:
\tJDK的动态代理是通过Proxy.newProxyInstance方法创建了一个类 , 这个类继承Proxy , 并且实现了在Proxy.newProxyInstance方法中设置的用户接口 , 这样这个类就可以执行接口的所有方法 , 而方法的具体实现则是指向父类Proxy的ProxyHandler的invoke方法 , 最终来实现代理 。


推荐阅读