美文网首页
深入理解:Java Proxy

深入理解:Java Proxy

作者: linheimx | 来源:发表于2016-12-13 11:32 被阅读162次

    代理模式

    ****代理模式的作用:
    为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    ****代理模式一般涉及到的角色:

    1. 抽象角色:声明真实对象和代理对象的共同接口;
    2. 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
    3. 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

    Proxy简介

    官方文档:

    Proxy defines methods for creating dynamic proxy classes and instances. A proxy class implements a declared set of interfaces and delegates method invocations to an InvocationHandler.

    中文翻译:

    1. 动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组)。
    1. 然后再利用您指定的classloader将该class加载进系统,最后生成这样一个类的对象,初始化该对象的一些值,如invocationHandler,以及所有的接口对应的Method成员。
    2. 初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象。

    实例分析

    1. 业务接口类

    public interface BusinessProcessor {
     public void processBusiness();
    }
    

    2. 业务实现类

    public class BusinessProcessorImpl implements BusinessProcessor {
     public void processBusiness() {
      System.out.println("----------> processing business..... <-----------");
     }
    }
    

    3. 业务代理类

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class BusinessProcessorHandler implements InvocationHandler {
    
     private Object target = null;
     
     BusinessProcessorHandler(Object target){
      this.target = target;
     }
     
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      System.out.println("You can do something here before process your business");
      Object result = method.invoke(target, args);
      System.out.println("You can do something here after process your business");
      return result;
     }
    
    }
    

    客户端应用类

    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Proxy;
    
    public class Test {
    
     public static void main(String[] args) {
      BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
      BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
      BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
      bp.processBusiness();
     }
    }
    
    

    现在我们看一下打印结果:

    通过结果我们就能够很简单的看出Proxy的作用了,它能够在你的核心业务方法前后做一些你所想做的辅助工作,如log日志,安全机制等等。

    分析:
    类一二没什么好说的。
    先看看类三吧。 实现了InvocationHandler接口的invoke方法。其实这个类就是最终Proxy调用的固定接口方法。

    Proxy不管客户端的业务方法是怎么实现的。当客户端调用Proxy时,它只会调用InvocationHandler的invoke接口,所以我们的真正实现的方法就必须在invoke方法中去调用。关系如下:

     BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
     BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
    
     BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
     bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();
    

    那么bp到底是怎么样一个对象呢。我们改一下main方法看一下就知道了:

     public static void main(String[] args) {
      BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
      BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
      BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
      bp.processBusiness();
      System.out.println(bp.getClass().getName());
     }
    

    输出结果:


    bp原来是个$Proxy0这个类的对象。那么这个类到底是长什么样子呢?好的。我们再写二个方法去把这个类打印出来看个究竟,是什么三头六臂呢?我们在main下面写如下两个静态方法。

    public static String getModifier(int modifier){
      String result = "";
      switch(modifier){
       case Modifier.PRIVATE:
        result = "private";
       case Modifier.PUBLIC:
        result = "public";
       case Modifier.PROTECTED:
        result = "protected";
       case Modifier.ABSTRACT :
        result = "abstract";
       case Modifier.FINAL :
        result = "final";
       case Modifier.NATIVE :
        result = "native";
       case Modifier.STATIC :
        result = "static";
       case Modifier.SYNCHRONIZED :
        result = "synchronized";
       case Modifier.STRICT  :
        result = "strict";
       case Modifier.TRANSIENT :
        result = "transient";
       case Modifier.VOLATILE :
        result = "volatile";
       case Modifier.INTERFACE :
        result = "interface";
      }
      return result;
     }
     
     public static void printClassDefinition(Class clz){
      
      String clzModifier = getModifier(clz.getModifiers());
      if(clzModifier!=null && !clzModifier.equals("")){
       clzModifier = clzModifier + " ";
      }
      String superClz = clz.getSuperclass().getName();
      if(superClz!=null && !superClz.equals("")){
       superClz = "extends " + superClz;
      }
      
      Class[] interfaces = clz.getInterfaces();
      
      String inters = "";
      for(int i=0; i<interfaces.length; i++){
       if(i==0){
        inters += "implements ";
       }
       inters += interfaces[i].getName();
      }
      
      System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
      System.out.println("{");
      
      Field[] fields = clz.getDeclaredFields();
      for(int i=0; i<fields.length; i++){
       String modifier = getModifier(fields[i].getModifiers());
       if(modifier!=null && !modifier.equals("")){
        modifier = modifier + " ";
       }
       String fieldName = fields[i].getName();
       String fieldType = fields[i].getType().getName();
       System.out.println("    "+modifier + fieldType + " "+ fieldName + ";");
      }
      
      System.out.println();
      
      Method[] methods = clz.getDeclaredMethods();
      for(int i=0; i<methods.length; i++){
       Method method = methods[i];
    
       String modifier = getModifier(method.getModifiers());
       if(modifier!=null && !modifier.equals("")){
        modifier = modifier + " ";
       }
       
       String methodName = method.getName();
       
       Class returnClz = method.getReturnType();
       String retrunType = returnClz.getName();
       
       Class[] clzs = method.getParameterTypes();
       String paraList = "(";
       for(int j=0; j<clzs.length; j++){
        paraList += clzs[j].getName();
        if(j != clzs.length -1 ){
         paraList += ", ";
        }
       }
       paraList += ")";
       
       clzs = method.getExceptionTypes();
       String exceptions = "";
       for(int j=0; j<clzs.length; j++){
        if(j==0){
         exceptions += "throws ";
        }
    
        exceptions += clzs[j].getName();
        
        if(j != clzs.length -1 ){
         exceptions += ", ";
        }
       }
       
       exceptions += ";";
       
       String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
       
       System.out.println("    "+methodPrototype );
       
      }
      System.out.println("}");
     }
    
    

    再改写main方法

     public static void main(String[] args) {
      BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
      BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
      BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
      bp.processBusiness();
      System.out.println(bp.getClass().getName());
      Class clz = bp.getClass();
      printClassDefinition(clz);
     }
    

    现在我们再看看输出结果:


    很明显,Proxy.newProxyInstance方法会做如下几件事:

    1. 根据传入的第二个参数interfaces动态生成一个类,实现interfaces中的接口。
      该例中即BusinessProcessor接口的processBusiness方法。
      并且继承了Proxy类,重写了hashcode,toString,equals等三个方法。

    2. 通过传入的第一个参数classloder将刚生成的类加载到jvm中。即将$Proxy0类load

    3. 利用第三个参数,调用$Proxy0的$Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象,并且用interfaces参数遍历其所有接口的方法,并生成Method对象初始化对象的几个Method成员变量

    4. 将$Proxy0的实例返回给客户端。

    现在好了。我们再看客户端怎么调就清楚了。

    1. 客户端拿到的是$Proxy0的实例对象,由于$Proxy0继承了BusinessProcessor,因此转化为BusinessProcessor没任何问题。
    BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
    
    1. bp.processBusiness();
      实际上调用的是$Proxy0.processBusiness();那么$Proxy0.processBusiness()的实现就是通过InvocationHandler去调用invoke方法啦!

    引用自

    http://blog.csdn.net/rokii/article/details/4046098
    http://blog.csdn.net/jianghuxiaoxiami/article/details/3403924

    相关文章

      网友评论

          本文标题:深入理解:Java Proxy

          本文链接:https://www.haomeiwen.com/subject/rqnvmttx.html