Hadoop源代码研读之路(4)

熟悉设计模式的人对于代理模式可能都不陌生。代理对象和被代理对象一般实现相同的接口,调用者与代理对象进行交互。代理的存在对于调用者来说是透明的,调用者看到的只是接口。代理对象则可以封装一些内部的处理逻辑,如访问控制、远程通信、日志、缓存等。比如一个对象访问代理就可以在普通的访问机制之上添加缓存的支持。这种模式在RMI和EJB中都得到了广泛的使用。传统的代理模式的实现,需要在源代码中添加一些附加的类。这些类一般是手写或是通过工具来自动生成。JDK 5引入的动态代理机制,允许开发人员在运行时刻动态的创建出代理类及其对象。

在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。熟悉AOP的人对这种使用模式应该不陌生。但是这种方式不需要依赖AspectJ等AOP框架。下面的代码用来代理一个实现了Resource接口的对象。所实现的功能也非常简单,那就是禁止使用Resource接口中的operationA方法。如果在Test类中传入一个实现Resource接口的对象,那么返回的实际就是一个代理对象,尝试在该对象上调用operationA方法就会抛出来异常。

package com.zzu.king;      public interface Resource {       public void operationA();       public void operationB();   }   package com.zzu.king;      public class ConcreteResource implements Resource {          @Override       public void operationA() {           System.out.println("Operation A.");       }          @Override       public void operationB() {           System.out.println("Operation B.");       }      }   package com.zzu.king;      import java.lang.reflect.InvocationHandler;   import java.lang.reflect.Method;   import java.lang.reflect.Proxy;      public class DynamicProxy implements InvocationHandler {       private Resource resource;                     public DynamicProxy() {           resource = new ConcreteResource();       }          public Resource create(){           Resource returnResource = null;                      returnResource = (Resource) Proxy.newProxyInstance(Resource.class.getClassLoader(),new Class[]{ Resource.class },this);                      return returnResource;       }          public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {           Object o = null;           if(method.getName().equals("operationA"))           //if(method.getName().equals("operation A"))            {               throw new UnsupportedOperationException();           }else{               o = method.invoke(resource, args);           }           return null;       }   }   package com.zzu.king;      public class Test {          /**       * @param args       */       public static void main(String[] args) {           DynamicProxy proxy = new DynamicProxy();           Resource resource = proxy.create();           resource.operationA();       }      }  

阅读上述代码:上述就是一个简单的动态代理的例子。我们可以看到Dynamic Proxy并没有实现Resource这个接口,但是包含了Resource接口实现类的实例;在Dynamic Proxy的create方法中,通过调用Proxy.newProxyInstance创建一个Proxy,并将该Proxy与Resource接口绑定,最后将Proxy显式类型转换成Resource接口类型并返回,这样调用者就可以通过Proxy调用interface定义的方法了;由于 Proxy与Resource接口绑定了,对Resource接口的方法调用,都会交由Proxy的invoke方法去处理。而invoke方法会根据不同的方法,或给以全新的实现,或直接将方法调用交给Proxy中包含的Resource接口实现类的实例去处理。综合上面所说的,作为一个Dynamic Proxy,它必须满足以下三个条件:

1、实现了InvocationHandler接口,实现接口中定义的invoke方法;

2、包含接口实现类的实例;

3、通过Proxy.newProxyInstance方法实现Proxy与接口之间的绑定

再来回顾一下定义

Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作   。

动态代理的定义:一个动态代理类在运行期implements一组interface,使得interface实现类的方法调用被分派至其他的类(另外的interface实现类或者任意的类)的方法。讲得更通俗一些,要了解动态代理,我们就要知道什么东西动态了,代理了什么?首先,一个Proxy代理了一组interface的方法。注意,代理的是interface,而不是Class,也不是abstract Class;其次,Proxy具有的型别由绑定的interface所决定的,动态就体现在此。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4241290d147808853f470c88378a13e0.html