读书人

JDK的动态署理深入解析(Proxy,Invoca

发布时间: 2012-10-28 09:54:44 作者: rapoo

JDK的动态代理深入解析(Proxy,InvocationHandler)(转)
调用处理器InvocationHandler,与被代理类(委托类)的实例想关联。

动态代理构造实例时必须和调用处理器InvocationHandler相关联,它不会替你作实质性的工作,在生成它的实例时你必须提供一个调用处理器InvocationHandler,由它接管实际的工作。



程序执行的结果如下:
the proxyObj is an animal!
the proxyObj isn't a dog!
被拦截的方法:info
I am a dog!
被拦截的方法:hashCode
$Proxy0

从结果可以看出以下几点:
1. proxyObj 是一个实现了目标对象接口的对象,而不同于目标对象。也就是说,这种代理机制是面向接口,而不是面向类的。
2. info方法(在接口中)被成功拦截了,hashCode方法也成功被拦截了,但意外的是,getClass方法(继承自Object 类的方法)并没有被拦截!!
3. 应用调试还可以看出Invocation接口中invoke方法的传入的proxy参数确实就是代理对象实例proxyObj

为何getClass()没有被拦截?proxy参数又有何用呢?
先不管,做一个试验看看。既然这个proxy参数就是代理实例对象,它理所当然和proxyObj是一样的,可以调用info等方法。于是我们可以在invoke方法中加上如下一条语句:

((IAnimal)proxy).info();
结果是:
the proxyObj is an animal!
the proxyObj isn't a dog!
被拦截的方法:info
被拦截的方法:info

.......

被拦截的方法:info
被拦截的方法:info

然后就是栈溢出

结果是很明显的,在invoke方法中调用proxy中的方法会再一次引发invoke方法,这就陷入了死循环,最终结果当然是栈溢出的。

可以在invoke方法中调用proxy.getClass(), 程序可以正常运行。但如果调用hashCode()方法同样会导致栈溢出。

通过上面的试验,可以得出一些初步结论,invoke 接口中的proxy参数不能用于调用所实现接口的方法。奇怪的是hashCode()和getClass()方法都是从Object中继承下来的方法,为什么一个可以另一个不可以呢?带首疑问到doc文档看一下Object中这两个方法,发现getClass()是定义为final的,而 hashCode()不是。难道是这个原因,于是找到一个非final方法,如equals试了一下,真的又会导致栈溢出;找另一个final方法如 wait(),试了一下,invoke又不拦截了。final 难道就是关键之处?

还有一个问题就是proxy有什么用?既然proxy可以调用getClass()方法,我们就可以得到proxy的Class类象,从而可以获得关于proxy代理实例的所有类信息,如方法列表,Annotation等,这就为我们提供的一个分析proxy的有力工具,如通过分析 Annotation分析方法的声明式事务需求。我想传入proxy参数应该是这样一个用意吧。

转自JDK的动态代理深入解析(Proxy,InvocationHandler)

读书人网 >编程

热点推荐