简介
关于JDK的动态代理,最为人熟知的可能要数spring AOP的实现,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现。那么,什么是JDK的动态代理呢?
JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。
使用JDK代理
JDK提供了Java.lang.reflect.Proxy类来实现动态代理,可通过它的newProxyInstance来获得代理实现类。
|
|
根据方法定义可知,此方法需要三个参数 下面分别构造
被代理的接口
|
|
接口的实现类
|
|
实现一个InvocationHandler
|
|
测试类
|
|
输出结果
|
|
原理及实现分析
从上面可知 JDK的使用很简单,但想要了解他的具体实现过程还是得从源码入手 这里的JDK版本是jdk1.7.0_80
newProxyInstance方法源码
|
|
从源码中可知 代理类是在getProxyClass0(..)方法中生成的,应该重点关注此方法,newInstance(..)方法中只是调用了传入的参数的newInstance方法
getProxyClass0方法源码
|
|
具体缓存逻辑我们不需要关心,只需要关注如何生成代理类的,ProxyClassFactory是Proxy类的一个静态内部类,它实现了WeakCache的内部接口BiFunction的apply方法,WeakCache是其代理缓存的实现
ProxyClassFactory源码
|
|
由源码可知,最终是由sun.misc包中ProxyGenerator类的generateProxyClass()方法生成的代理类
generateProxyClass源码
|
|
由源码得知,根据参数saveGeneratedFiles值来决定是否把生成的代理类保存到本地 继续跟跟踪源码
|
|
GetBooleanAction实际上是调用Boolean.getBoolean(propName)来获得的,而Boolean.getBoolean(propName)调用了System.getProperty(name),所以我们可以设置sun.misc.ProxyGenerator.saveGeneratedFiles这个系统属性为true来把生成的class保存到本地文件来查看。
重新执行测试类
|
|
生成的代理类源码
运行测试类 在目录com/sun/proxy下面可找到$Proxy0.class类,对其进行反编译
|
|
从源码中可以看到,动态生成的代理类有如下特性:
- 代理类继承了Proxy类,实现了代理的HelloWorld接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
- 提供了一个使用InvocationHandler作为参数的构造方法。
- 代理类实现代理接口的sayHello方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。
spring AOP
从上面的源码分析中我们可以大致了解到spring aop的各种拦截如何实现,很明显 无非就是在method.invoke方法调用前后做文章 代码如下
|
|
总结
- 底层最终是由sun.misc包中ProxyGenerator类的generateProxyClass()方法生成的代理类
- 通过Proxy.newProxyInstance()生成代理类的实例对象,创建对象时传入InvocationHandler类型的实例。
- 调用新实例的方法 world.sayHello(“name”);即调用传入的InvocationHandler类中的invoke()方法。
本文融合多篇文章整理而成,具体文章连接已遗失,如有侵权请告知