1.java的动态代理可以帮助我们动态的生成字节码文件。 例如: Class clazz=Proxy.getProxyClass(List.class.getClassLoader(), List.class); 这样我们就建立了一个字节码文件,我们可以通过反射来操作字节码文件做很多事情,例如获取clazz的所有字段、方法、构造方法等。还可以获取器名字(这个名字是$Proxy0,可以通过System.out.println(clazz.getName());获取) 这里我们获取其方法和构造方法。 通过获取,我们可以知道,其只有一个有参数的构造方法,参数类型是java.lang.reflect.InvocationHandler。 于是我们可以获取这个带java.lang.reflect.InvocationHandler参数的构造函数,然后newInstance一个对象。 代码如下: Constructor constructor = clazz.getConstructor(InvocationHandler.class); constructor.newInstance(new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub return method.invoke(l, args); } }); 由于java.lang.reflect.InvocationHandler是一个接口,所以我们这里采用了匿名实现的方式。其实大多数情况下,我们需要的是。一个实现了InvocationHandler接口的类。然后在invoke方法做一些自己的事情就可以了。这里要注意的一点就是invoke方法的method.invoke(l, args);这个参数一定不要使用代理对象的。也就是不要使用proxy,而是使用传进来的源对象。 这是为什么呢?解释一下。我们都知道,代理对象和源对象里的方法是一样的。只是代理对象有一个带java.lang.reflect.InvocationHandler参数的构造函数。我们应该知道,构造函数的作用,就是初始化字段什么的。所以我们可以断定,代理类里面有一个InvocationHandler类型的字段(假设的,其实在clazz中获取的字段中看不出有这个)。 例如,我们执行List的代理类的方法size()的时候。 其实是执行: public class $Proxy0{ public int size{ return invoke(this, this.getClass().getMethod("size"), new Object[] {}); } } 如果我们在invoke(this, Method method, Object[] args);{dy}个参数里面写上 代理类的话,将会是死循环。 就是执行代理类的invoke方法,而invoke方法又执行代理类的invoke方法,如此反复。因此这个要用源类。 2.其实以上的过程可以被简化,以上的过程是创建字节码,根据字节码获取构造器、根据构造器new一个代理对象。其实Proxy的Proxy.newProxyInstance(loader, interfaces, h);方法已经帮我们全部搞定了。我们要做的就是创建一个InvocationHandler实现类,然后把自己的源类传递到这个实现类中,就可以得到代理对象了。 http://longdechuanren.javaeye.com/blog/621777 |