黑马程序员技术交流社区
标题:
关于学习动态代理的一点心得
[打印本页]
作者:
黎志文
时间:
2013-7-21 15:12
标题:
关于学习动态代理的一点心得
本帖最后由 黎志文 于 2013-7-21 15:20 编辑
之前对代理很迷惑,对它没有一点点思路,其实最主要的,是对代理中涉及到的三个方法及其之间的参数传递迷糊,现将这三个方法总结如下,希望能够给正在对代理同样迷糊的童鞋一点帮助:
1)代理类的方法:代理类的方法一是来自目标类实现的接口中,二是来自Object这个超类。获取接口中的方法,是为了接下来给目标类做代理打下必备基础,
* 这些方法在jvm生成的代理类中,就已全被jvm复写了,至于复写的具体内容是什么,我们无法得知,只能大致地去推断,但是有一点可以明确,在这些复写好了的
* 每个方法的内部,最核心的是调用了一个方法,该方法就是InvocationHandler接口中的invoke(Object proxy,Method method,Object[] obj)方法,我
* 们知道,要调用一个方法,就必须给此方法传递实参(如果该方法存在形参的话), 代理类中每个实现接口的方法的内部都调用了该方法,那么就须给此方法传递
* 实参。
* 这里以Collection中的add(Object obj)方法为例,假设代理类实现了Collection接口,那么代理类在复写add方法时,在add方法的内部,调用invoke
* 方法,并给该方法传递的第一个实参是this,也就是一个代理类对象,传递的第二个实参就是this.getClass().getMetod("add",Object.class),我给它起个
* 名字,叫addMethod,即通过反射 的方式将add方法的名称传递给invoke方法,传递的第三个参数就是add方法中的参数obj,当然,如果代理类的方法存在多个形参,
* 这里就必须将这些形参名称全部传递给invoke方法的第三个参数(这也就是为何invoke方法的第三个参数是一个数组的原因了,用于接收代理方法中的所有参数),
* 将add方法的名称及其参数传递给invoke方法有什么意义呢?请看下面。
*
* 2)InvocationHandler接口中的invoke方法:这个方法在接收了上述代理类方法传递给它的参数之后(主要是代理类方法的名称及其参数),我们就可以在
* invoke方法的内部使用这两个参数了,怎么使用呢?可以通过目标类对象,来使用这两个参数:method.invoke(target,obj),这里的method就是add方法,
* obj就代理类add方法中的参数。
*
* 3)目标类对象调用的方法:method.invoke(target,args),用目标类对象target来调用method方法(这里的method就已经是add方法了),并给此方法
* 传递的参数就是obj,
* 总之,代理类的add方法将它的名称,以及它接收到的参数传给invoke方法,invoke方法又在其内部通过目标类对象来调用这两个参数。这样到最后,其实还是目标
* 类对象在调用add方法。
*
* 根据我的理解,可以推断代理类的add方法是这样定义的
* public boolean add(Object obj)
* {
* Object retVal = handler.invoke(this,this.getClass().getMethod("add",Object.class),new Object[]{obj});
* return (Boolean)retVal; //因为invoke方法的返回值其实就是将目标类方法的返回值提升至Object,所以这里将这个返回值强转成它原本的类型,再传给代理类方法。
* }
* 而我们在创建InvocationHandler接口的子类对象时,要复写invoke方法,
* public Object invoke(Object proxy,Method method,Object[] args)
* {
* //自定义的拓展代码
* Object retVal = method.invoke(target,args); //将目标类调用add方法的返回值传给invoke方法
* //自定义的拓展代码
* return retVal;
* }
* add方法内部调用invoke方法,并给它传递了参数,method接收了add方法的信息,args接收了add方法参数的信息,所以method.invoke(target,args)其实
* 就是目标类对象target在调用add方法,给该方法传递的参数就是代理类add方法中的参数。当然,我们不在invoke方法内部写method.invoke(target,args)
* 也是可以的,但这样一来该代理类方法就没有起到代理的本意。所以,我们在复写invoke方法时,要注意,一定要加上这部分代码。至于拓展的代码,则可根据需
* 要去自定义。
*
* proxy.add("hello")---将方法信息和参数信息传递给---> handler.invoke方法 -----再通过目标类对象去使用这两个信息---> method.invoke(target,args)
* ↓
* proxy.add方法 <-------------------再传给------------------ handler.invoke方法 <-----------------------------传给---------------------------- 返回值。
作者:
杨兴庭
时间:
2013-7-21 19:04
很不错的总结。。。。。{:soso_e179:}
作者:
梦想蓝色天空
时间:
2013-7-21 21:45
正在学习代理。。学习了
作者:
梦想蓝色天空
时间:
2013-7-21 21:54
正在学习代理。。学习了
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2