首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

总结一上反射的一个应用-动态代理

2012-08-26 
总结一下反射的一个应用--动态代理? ? ? 把《Java核心技术》与《Java编程思想》翻过去。反射一部分讲的大同小异

总结一下反射的一个应用--动态代理

? ? ? 把《Java核心技术》与《Java编程思想》翻过去。反射一部分讲的大同小异。总体来说《Java核心技术》讲得比较拖沓,但是比较全面,《Java编程思想》讲得比较简略,第一遍看可能看不懂。

? ? ? 因为之前有仔细研究过几个框架中XML配置文件的语法,发现反射中代理类的应用在框架中虽然是透明的,但是我依然能够感受它的存在。我甚至怀疑AOP的对象不是由编译器生成合成对象实现的,而是由代理对象实现的,因为面向接口编程的思想到处都是。

?

? ? ?一、 什么是代理类。

?

? ? ?现实中不可能为每个接口都准备好一个适配器类,毕竟Java并不支持多基类继承。有时候我们可能需要动态地生成一个对象,它的内部实现只是对某些方法的一个封装。通过这些封装我们可以实现AOP,比如在某个类的方法执行前、执行后写日志等等。它包含一个类加载器、一些接口列表和一个调用处理器类。

?

? ? ?一句话来讲,代理类就是在接口和接口实现类之间加上一个中间层,实现一些中间层特有的操作。

?

?

? ? ?二、如何构造一个调用处理器类?

?

?

? ? 1 代理类必须实现InvocationHandler接口,幸运的是,我们只需要重写它的一个抽象方法--Invoke()。

?

? ? 2 这个代理类中必须有一个局部动态代理对象--注意区分,代理处理类中还自带一个局部动态代理对象。这一般可以通过构造器获得。

?

? ? 3 Invoke方法的写法:

? ? ? ? 参数1 proxy对象。

? ? ? ? 参数2 一个method对象--这是一个高阶函数式的写法。

? ? ? ? 参数3 一个arg数组。

?

? ? ? ? 必须抛出Throwable类型的异常。

?

?

? ? ? ? 函数体内:

?

? ? ? ? ?(1) 加入自己想要的内容。

? ? ? ? ?(2) return method.invoke(proxy,args)。即使用反射的方法确实地执行这个方法method。

?

? ? ? ? 一句话来讲,调用处理类就是必须以接口实现类为构造参数,对接口的每一个方法都要invoke一下的类。

?

?

? ? ?三、如何创建动态代理对象?

?

?

? ? 使用静态工厂的方法,Proxy.newProxyInstance()。

? ? 它的参数:

? ? 1 一个类加载器,一般使用一个已经被加载的对象a上使用 a.class.getClassLoader()获取。

? ? 2 一个希望实现的接口列表。注意,是一个Class类型的数组。

? ? 3 以及一个调用处理器的对象,必须用一个实际上实现了接口的引用对象对它进行初始化。

?

? ?创建完毕后,记得将它转型为想要实现的某个接口类型,才能给引用赋值。

?

?

? ? 四、动态代理对象如何工作?

?

? ? 当这个代理对象x被赋予某种接口a的引用,然后调用a.b()方法时,虚拟机会执行以下操作:

?

? ?1 将请求转发到这个动态代理对象的调用处理器类。这个调用处理器类的构造器获得x的引用,将它赋予自己的局部动态代理对象X。b

? ?2 执行invoke方法,第一个参数传入局部动态代理对象X,第二个参数传入b(),第三个参数传入接口调用时赋予的参数(如果有的话)。

? ?3 执行invoke方法体,退出。

?

? ?每次调用x的任何一个方法,invoke方法都会被调用,每次调用第一个参数都是一样的。

?

?

?

?

刚写的一段示例代码:

?

?

?

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/* * 这个类很像AOP的一种用法,在方法执行以前加入某些操作,只有中间层才能做到。*/interface A{void b();void c(String d);}class E implements A{public void b(){System.out.println("This is b.");}public void c(String d){System.out.println("This is c's d" + d);}}class myInvocationHandler implements InvocationHandler{private Object obj;public myInvocationHandler(Object obj){this.obj = obj;}public Object invoke(Object proxy, Method method,Object[] args) throws Throwable{System.out.println("This is the object of " + proxy.getClass().getName());System.out.println("The method name is  " + method.getName());if(args != null)//如果没有这个句子,会出现一个空指针异常。for(Object arg : args)System.out.println("The argument is  " + arg);return method.invoke(obj, args);//极度要注意,这里的obj与proxy不同,proxy的传值我们没有办法控制,我们只能控制object的。}}public class MyProxy {/** * @param args */public static void main(String[] args) {E e = new E();A a = (A) Proxy.newProxyInstance(e.getClass().getClassLoader(),//这个classloader的获取做法很奇怪。但是却不能用null。 如果不是强制转换为A类型的话,就可以了。new Class[] {A.class}, new myInvocationHandler(e));//这就把e传进调用处理器里面去了。Object b = Proxy.newProxyInstance(null,new Class[] {Comparable.class }, new myInvocationHandler(e));//如果要实现的接口不是自定义的,就可以使用null作为类加载器了。如果使用a.class,则必须使用a.getClass.getClassLoader()方法。a.b();a.c("liang");a.c("123");}}
?

热点排行