zoukankan      html  css  js  c++  java
  • java之静态代理与动态代理

    先看看静态代理是如何操作的

    定义接口:

    1 public interface Person {
    2     public void sayHello(String content, int age);
    3     public void sayGoodBye(boolean seeAgin, double time);
    4 }

    实际的类:

     1 public class Student implements Person{
     2  
     3     @Override
     4     public void sayHello(String content, int age) {
     5         // TODO Auto-generated method stub
     6         System.out.println("student say hello" + content + " "+ age);
     7     }
     8  
     9     @Override
    10     public void sayGoodBye(boolean seeAgin, double time) {
    11         // TODO Auto-generated method stub
    12         System.out.println("student sayGoodBye " + time + " "+ seeAgin);
    13     }
    14 }

    代理类:

     1 public class ProxyTest implements Person{
     2     
     3     private Person o;
     4     
     5     public ProxyTest(Person o){
     6         this.o = o;
     7     }
     8  
     9     @Override
    10     public void sayHello(String content, int age) {
    11         // TODO Auto-generated method stub
    12         System.out.println("ProxyTest sayHello begin");
    13         //在代理类的方法中 间接访问被代理对象的方法
    14         o.sayHello(content, age);
    15         System.out.println("ProxyTest sayHello end");
    16     }
    17  
    18     @Override
    19     public void sayGoodBye(boolean seeAgin, double time) {
    20         // TODO Auto-generated method stub
    21         System.out.println("ProxyTest sayHello begin");
    22         //在代理类的方法中 间接访问被代理对象的方法
    23         o.sayGoodBye(seeAgin, time);
    24         System.out.println("ProxyTest sayHello end");
    25     }
    26 
    27 public static void main(String[] args) {
    28         // TODO Auto-generated method stub
    29         //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问
    30         Student s = new Student();
    31         //创建代理类对象
    32         ProxyTest proxy = new ProxyTest(s);
    33         //调用代理类对象的方法
    34         proxy.sayHello("welcome to java", 20);
    35         System.out.println("******");
    36         //调用代理类对象的方法
    37         proxy.sayGoodBye(true, 100);
    38  
    39     }
    40  
    41 }

    可以看到,静态代理类要求实现与实际类型相同的接口,这个虽然在某些情况下有使用场景,但是其实扩展起来很麻烦,需要一个个的进行重载,相比之下,动态代理就好多了。

    动态代理也需要一个代理类,实现特定的接口InvocationHandler:

     1 public class MyInvocationHandler implements InvocationHandler{
     2     
     3     private Object object;
     4     
     5     public MyInvocationHandler(Object object){
     6         this.object = object;
     7     }
     8  
     9     @Override
    10     public Object invoke(Object proxy, Method method, Object[] args)
    11             throws Throwable {
    12         // TODO Auto-generated method stub
    13         System.out.println("MyInvocationHandler invoke begin");
    14         System.out.println("proxy: "+ proxy.getClass().getName());
    15         System.out.println("method: "+ method.getName());
    16         for(Object o : args){
    17             System.out.println("arg: "+ o);
    18         }
    19         //通过反射调用 被代理类的方法
    20         method.invoke(object, args);
    21         System.out.println("MyInvocationHandler invoke end");
    22         return null;
    23     }
    24     
    25     public static void main(String [] args){
    26         //创建需要被代理的类
    27         Student s = new Student();
    28         //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
    29         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    30         //获得加载被代理类的 类加载器
    31         ClassLoader loader = Thread.currentThread().getContextClassLoader();
    32         //指明被代理类实现的接口
    33         Class<?>[] interfaces = s.getClass().getInterfaces();
    34         // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法
    35         MyInvocationHandler h = new MyInvocationHandler(s);
    36         //生成代理类
    37         Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);
    38         //通过代理类调用 被代理类的方法
    39         proxy.sayHello("yujie.wang", 20);
    40         proxy.sayGoodBye(true, 100);
    41         System.out.println("end");
    42     }
    43  
    44 }

    这个灵活性就好多了,不用关心自己代理的类到底有多少方法,只用实现一个invoke方法,去做自己想做的事情就好,如果需要根据特定的方法做事情,可能就需要根据method判断了,不如静态代理写在重载方法中感觉好。

    那么,java到底是怎么实现动态代理的,不妨反编译一下,拿到的结果如下,可以看到其实是jvm帮你做了静态代理的事情:

      1 public final class $Proxy0 extends Proxy implements Person{
      2   private static Method m4;
      3   private static Method m1;
      4   private static Method m0;
      5   private static Method m3;
      6   private static Method m2;
      7   
      8   public $Proxy0(InvocationHandler paramInvocationHandler)
      9     throws 
     10   {
     11     super(paramInvocationHandler);
     12   }
     13    //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
     14   public final void sayGoodBye(boolean paramBoolean, double paramDouble)
     15     throws 
     16   {
     17     try
     18     {
     19     // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
     20     // m4为代理类通过反射获得的Method
     21       this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) });
     22       return;
     23     }
     24     catch (Error|RuntimeException localError)
     25     {
     26       throw localError;
     27     }
     28     catch (Throwable localThrowable)
     29     {
     30       throw new UndeclaredThrowableException(localThrowable);
     31     }
     32   }
     33   
     34   public final boolean equals(Object paramObject)
     35     throws 
     36   {
     37     try
     38     {
     39       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
     40     }
     41     catch (Error|RuntimeException localError)
     42     {
     43       throw localError;
     44     }
     45     catch (Throwable localThrowable)
     46     {
     47       throw new UndeclaredThrowableException(localThrowable);
     48     }
     49   }
     50   
     51   public final int hashCode()
     52     throws 
     53   {
     54     try
     55     {
     56       return ((Integer)this.h.invoke(this, m0, null)).intValue();
     57     }
     58     catch (Error|RuntimeException localError)
     59     {
     60       throw localError;
     61     }
     62     catch (Throwable localThrowable)
     63     {
     64       throw new UndeclaredThrowableException(localThrowable);
     65     }
     66   }
     67   //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 
     68   public final void sayHello(String paramString, int paramInt)
     69     throws 
     70   {
     71     try
     72     {
     73       // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法
     74       // m4为代理类通过反射获得的Method
     75       this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) });
     76       return;
     77     }
     78     catch (Error|RuntimeException localError)
     79     {
     80       throw localError;
     81     }
     82     catch (Throwable localThrowable)
     83     {
     84       throw new UndeclaredThrowableException(localThrowable);
     85     }
     86   }
     87   
     88   public final String toString()
     89     throws 
     90   {
     91     try
     92     {
     93       return (String)this.h.invoke(this, m2, null);
     94     }
     95     catch (Error|RuntimeException localError)
     96     {
     97       throw localError;
     98     }
     99     catch (Throwable localThrowable)
    100     {
    101       throw new UndeclaredThrowableException(localThrowable);
    102     }
    103   }
    104   
    105   static
    106   {
    107     try
    108     {//代理类通过反射 获得的接口方法Method
    109       m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye", new Class[] { Boolean.TYPE, Double.TYPE });
    110       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
    111       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    112       //代理类通过反射 获得的接口方法Method
    113       m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String"), Integer.TYPE });
    114       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    115       return;
    116     }
    117     catch (NoSuchMethodException localNoSuchMethodException)
    118     {
    119       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    120     }
    121     catch (ClassNotFoundException localClassNotFoundException)
    122     {
    123       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    124     }
    125   }
    126 }

    本文参考了https://blog.csdn.net/u011784767/article/details/78281384

  • 相关阅读:
    237. Delete Node in a Linked List
    430. Flatten a Multilevel Doubly Linked List
    707. Design Linked List
    83. Remove Duplicates from Sorted List
    160. Intersection of Two Linked Lists
    426. Convert Binary Search Tree to Sorted Doubly Linked List
    142. Linked List Cycle II
    类之间的关系
    初始化块
    明确类和对象
  • 原文地址:https://www.cnblogs.com/029zz010buct/p/10497605.html
Copyright © 2011-2022 走看看