经常听到动态代理,总是觉得是很复杂的东西,今天通过设置特殊参数轻松理解动态代理。
代码实现
目标方法与代理类代码如下图:
这里为了展示把三个类放到一个文件中,首先是一个接口包含一个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方法中设置的用户接口,这样这个类就可以执行接口的所有方法,而方法的具体实现则是指向父类Proxy的ProxyHandler的invoke方法,最终来实现代理。
Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!
领取专属 10元无门槛券
私享最新 技术干货