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

java Proxy类的议论

2013-11-23 
java Proxy类的讨论? ? 这里的关系也比较好理解,我们既然从用户使用的角度来说,Proxy类和具体实现类看起来

java Proxy类的讨论

? ? 这里的关系也比较好理解,我们既然从用户使用的角度来说,Proxy类和具体实现类看起来没什么区别。那必然从用户的角度他们是可以互换的。所以他们必然需要实现同一个接口才可能。而这种模式典型的示例代码如下:

Contract interface:

? ? 这里,每个Decorator都有一个指向同样接口的引用。它本身只是做一些代理。继承Decorator的类会针对具体特性做一些增强。这个Decorator的类本身就相当于是一个Proxy。关于Decorator pattern的详细描述可以参考我的这篇文章。从这些关系我们可以看到,Decorator pattern增加的继承可以使得代理增加的特性更加灵活和丰富。

? ? 至于Adaptor pattern的描述,其本身更加简单:

java Proxy类的议论

? ? 我们这里的Adapter就是一个Proxy,他本身要引用另外一个Adaptee的特性,只是要使得他本身符合接口Target的规约而已。

? ? 现在,到这一步的时候,我们发现其实原来很多的应用方式都用到了Proxy模式的思想,只是平时不太留意到而已。我们手工编码实现的Proxy需要有明确的接口规约,这样才能模拟出这样的结果来。在一些情况下,如果我们需要动态的生成一些Proxy类的话,有没有什么好的办法呢?因为对于一些接口来说,每次我们通过手工的去实现他们其实从写代码的角度来说挺没劲的,来来去去就是那么个套路。既然这些事情是如此无趣,能不能让程序给我们生成呢?

Proxy类介绍

? ? 在Java里有专门用于动态代理类生成的方法,就是java.lang.reflect.Proxy。它采用反射的机制来调用原来的被封装方法。我们以前面的示例为基础来看看用Proxy类封装代理之后的常用做法。

? ? 前面的示例里我们首先定义了接口Contract和具体的实现Impl类。这里就不重复。为了能够代理这个类的功能,我们首先定义一个类DynamicProxyHandler:

? ? 这个ProxyHandler类实现接口InvocationHandler。我们在实现的invoke方法里添加了一些自己定义的信息。然后通过method.invoke方法来调用目标对象的方法,并返回调用的结果。我们可以说这里是我们定义自己定制部分特性的切入点,在代理类被调用的时候,触发的就是这个方法。同时被代理的对象将作为构造函数的参数传递进来。

? ? 我们再来看是怎么使用这个DynamicProxyHandler将目标对象包装起来:

public static Object newProxyInstance(ClassLoader loader,                                          Class<?>[] interfaces,                                          InvocationHandler h)        throws IllegalArgumentException    {        if (h == null) {            throw new NullPointerException();        }        /*         * Look up or generate the designated proxy class.         */        Class<?> cl = getProxyClass(loader, interfaces);        /*         * Invoke its constructor with the designated invocation handler.         */        try {            Constructor cons = cl.getConstructor(constructorParams);            return cons.newInstance(new Object[] { h });        } catch (NoSuchMethodException e) {            throw new InternalError(e.toString());        } catch (IllegalAccessException e) {            throw new InternalError(e.toString());        } catch (InstantiationException e) {            throw new InternalError(e.toString());        } catch (InvocationTargetException e) {            throw new InternalError(e.toString());        }    }

? ? 这个方法其实比较简单,就是通过调用类本身的getProxyClass方法来获取到一个我们代理后生成的Class对象,然后再通过反射调用该对象的构造函数来生成目标对象。那么这个getProxyClass是怎么来生成目标Class对象呢?我们再深入的看看。

? ? getProxyClass方法本身就需要一个能够实现指定一系列接口的类,而且需要这个类是动态生成的。当然,这个类既然是动态生成的,我们就需要针对接口里所有的方法进行审核。如果我们对jvm再深入理解一点的话,会发现一般java里生成的Class文件有一个固定的格式可以遵循的。比如class文件里指明所使用的java的版本,这个类是接口还是类,里面的成员和方法等信息。既然我们需要一个这样的类,我们完全可以通过一个模板的类来生成这样的类文件。以后我们再通过类加载器将其加载进来就可以了。

? ? getProxyClass方法通过委托ProxyGenerator来生成这个文件,然后再加载进来。而getProxyClass方法主要是检查这些接口的列表是否重复了,这些接口是否都声明在同一个package里面。然后将生成后的Class对象放到一个weak reference的缓存里。这个几百行的方法里其实主要就是做一些检查工作,没什么特殊的地方。

?

总结

? ? Proxy模式以及它的一些应用其实平时使用的并不多。更多的时候是在一些J2EE的应用里,比如生成RMI的stub,以前要用工具类rmic来做,现在基本上就是依赖的Proxy。另外,Proxy的思想里也可以用到AOP的应用上。虽然这部分比较少见,但是它和jvm的很多地方关系比较密切,比如class文件的动态生成。以前我们要生成这些需要自己写出来然后用javac编译器来生成,这里自动按照指定的规约来生成,确实比较少见。

?

参考材料

core java volumn I

head first design patterns

http://www.ibm.com/developerworks/java/library/j-jtp08305/index.html

http://www.infoq.com/cn/articles/cf-java-reflection-dynamic-proxy

http://openjdk.java.net/

热点排行