十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
作者:张丰哲
创新互联建站服务项目包括会宁网站建设、会宁网站制作、会宁网页制作以及会宁网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,会宁网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到会宁省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
原文:https://www.jianshu.com/p/58759fef38b8
在Java领域,动态代理应用非常广泛,特别是流行的Spring/MyBatis等框架。JDK本身是有实现动态代理技术的,不过要求被代理的类必须实现接口,不过cglib对这一不足进行了有效补充。本篇博客将涉及2个话题:第一,JDK动态代理的实现原理,带你探索动态代理的实质面目;第二,自己动手写代码去实现JDK动态代理,去创造世界!
先写一个例子,感性认识下动态代理~
业务接口:
interface
业务实现类:
interface impl
业务处理类:
Handler
测试类:
test
运行结果:
result
在JDK动态代理中涉及如下角色:
业务接口Interface、业务实现类target、业务处理类Handler、JVM在内存中生成的动态代理类$Proxy0
动态代理原理图:
动态代理的真实面目
说白了,动态代理的过程是这样的:
第一:Proxy通过传递给它的参数(interfaces/invocationHandler)生成代理类$Proxy0;
第二:Proxy通过传递给它的参数(ClassLoader)来加载生成的代理类$Proxy0的字节码文件;
我们来看看上面例子中生成的$Proxy0的模样:
$Proxy0
首先,$Proxy是实现了我们的业务接口(Man)的,所以客户端显然可以调用业务接口的方法。
其次,注意到$Proxy是继承自Proxy,并通过构造方法将业务处理类传入给父类Proxy进行初始化。(实质上,你可以看看源码,在Proxy中存在protected InvocationHandler h;)
初始化Proxy
findObject
很明显,我们看到了业务接口的方法是如何被调用的:
最终都是回调业务处理类(具体的Handler)的invoke方法完成调用!
在上面,我们已经分析了JDK动态代理的整个调用过程,接下来,我们就来手写实现它吧!
先来看一眼图:
手写实现JDK动态代理
自定义InvocationHandler:
MyInvocationHandler
实现MyInvocationHandler的业务处理Handler:
MyHandler
自定义类加载器MyClassLoader:
MyClassLoader
为什么要定义一个自定义的类加载器呢?它的作用是什么呢?
要知道,我们是想手写JDK动态代理,那么我们将自己在内存中生成动态代理类,那么我们如何加载呢?这时候,就可以利用自定义的类加载器做到!
上述代码,重写了findClass方法,就是为了在指定路径下加载指定的字节码文件。
自定义MyProxy:
MyProxy
MyProxy的作用就相当于JDK的Proxy。MyProxy做了哪些事情呢?
第一:需要根据interfaces接口构造出动态代理类需要的方法。(其实就是利用反射获取)
第二:把动态生成的代理类(即.java文件)进行编译,生成字节码文件(即.class文件),然后利用类加载进行加载
第三:动态代理类进行加载后,利用反射机制,通过构造方法进行实例化,并在实例化时,初始化业务Hanlder
看一下MyProxy的其他方法:
编译方法
getMethodString方法
运行结果
我们来看一眼生成的$MyProxy0:
$MyProxy0
OK,到这里,整个JDK的动态代理的实现原理以及手写实现就结束了,你学到了么?