• [编织消息框架][JAVA核心技术]jdk动态代理


    需要用到的工具  jdk : javac javap

    class 反编译 :JD-GUI http://jd.benow.ca/

    先来看下jdk动态代理跟native性能比较

     1 package com.eyu.onequeue;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 
     7 public class TestProxy {
     8     public interface UserService {
     9     public String getName(int id);
    10 
    11     public Integer getAge(int id);
    12     }
    13 
    14     public static class UserServiceImpl implements UserService {
    15 
    16     @Override
    17     public String getName(int id) {
    18         return "name : " + id;
    19     }
    20 
    21     @Override
    22     public Integer getAge(int id) {
    23         return id;
    24     }
    25     };
    26 
    27     public static void main(String[] args) {
    28     testNative();
    29     testJdk();
    30     }
    31 
    32     public static void testJdk() {
    33     UserService impTarget = new UserServiceImpl();
    34     // 代理处理逻辑
    35     InvocationHandler handler = new InvocationHandler() {
    36 
    37         @Override
    38         public Object invoke(Object target, Method method, Object[] args) throws Throwable {
    39         return method.invoke(impTarget, args);
    40         }
    41     };
    42     // Proxy.newProxyInstance(ClassLoader/**ClassLoader 没有特别处理 拿默认即可 **/,
    43     // Class<?>[]/**代理接口类**/, InvocationHandler /**代理处理逻辑**/)
    44     UserService proxy = (UserService) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), new Class[] { UserService.class }, handler);
    45 
    46     run("jdk", proxy);
    47     }
    48 
    49     public static void testNative() {
    50     UserService impTarget = new UserServiceImpl();
    51     run("native", impTarget);
    52     }
    53 
    54     private static void run(String tag, UserService impTarget) {
    55     int c = 15;
    56     System.out.println();
    57     while (c-- > 0) {
    58         long start = System.currentTimeMillis();
    59         for (int i = 0; i < 10000000; i++) {
    60         impTarget.getName(11);
    61         }
    62         long end = System.currentTimeMillis();
    63         System.out.print(tag + ": " + (end - start) + " ");
    64     }
    65     }
    66 }

    运行结果:

    native: 175 native: 182 native: 126 native: 172 native: 126 native: 127 native: 127 native: 126 native: 127 native: 126 native: 126 native: 128 native: 126 native: 127 native: 126
    jdk: 214 jdk: 170 jdk: 169 jdk: 169 jdk: 170 jdk: 170 jdk: 170 jdk: 170 jdk: 170 jdk: 172 jdk: 169 jdk: 172 jdk: 169 jdk: 171 jdk: 169

    先运行预热,看出执行五次之后比较稳定

    jdk动态代理使用非常简单,使用Proxy.newProxyInstance 静态方法即可

    接下来我们看下class指令

    javac -encoding UTF-8 -d . TestProxy.java

    javap -v comeyuonequeueTestProxy.class > s.txt

    其中

     // Method java/lang/reflect/Proxy.newProxyInstance:(Ljava/lang/ClassLoader;[Ljava/lang/Class;Ljava/lang/reflect/InvocationHandler;)Ljava/lang/Object;

    没有详细看到代理类指令

    运行时生成的动态代理对象是可以导出到文件的,方法有两种

    1. 在代码中加入System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    2. 在运行时加入jvm 参数 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

    我们在main方法加一行System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 然后执行一下

    1  public static void main(String[] args) {
    2     System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    3      //省略
    4  }

    这时在包下会多出$Proxy0.class文件

    proxy0.class用jd-gui打开

      1 package com.sun.proxy;
      2 
      3 import com.eyu.onequeue.TestProxy.UserService;
      4 import java.lang.reflect.InvocationHandler;
      5 import java.lang.reflect.Method;
      6 import java.lang.reflect.Proxy;
      7 import java.lang.reflect.UndeclaredThrowableException;
      8 
      9 public final class $Proxy0
     10   extends Proxy
     11   implements TestProxy.UserService
     12 {
     13   private static Method m1;
     14   private static Method m2;
     15   private static Method m3;
     16   private static Method m4;
     17   private static Method m0;
     18   
     19   public $Proxy0(InvocationHandler paramInvocationHandler)
     20   {
     21     super(paramInvocationHandler);
     22   }
     23   
     24   public final boolean equals(Object paramObject)
     25   {
     26     try
     27     {
     28       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
     29     }
     30     catch (Error|RuntimeException localError)
     31     {
     32       throw localError;
     33     }
     34     catch (Throwable localThrowable)
     35     {
     36       throw new UndeclaredThrowableException(localThrowable);
     37     }
     38   }
     39   
     40   public final String toString()
     41   {
     42     try
     43     {
     44       return (String)this.h.invoke(this, m2, null);
     45     }
     46     catch (Error|RuntimeException localError)
     47     {
     48       throw localError;
     49     }
     50     catch (Throwable localThrowable)
     51     {
     52       throw new UndeclaredThrowableException(localThrowable);
     53     }
     54   }
     55   
     56   public final String getName(int paramInt)
     57   {
     58     try
     59     {
     60       return (String)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
     61     }
     62     catch (Error|RuntimeException localError)
     63     {
     64       throw localError;
     65     }
     66     catch (Throwable localThrowable)
     67     {
     68       throw new UndeclaredThrowableException(localThrowable);
     69     }
     70   }
     71   
     72   public final Integer getAge(int paramInt)
     73   {
     74     try
     75     {
     76       return (Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
     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 int hashCode()
     89   {
     90     try
     91     {
     92       return ((Integer)this.h.invoke(this, m0, null)).intValue();
     93     }
     94     catch (Error|RuntimeException localError)
     95     {
     96       throw localError;
     97     }
     98     catch (Throwable localThrowable)
     99     {
    100       throw new UndeclaredThrowableException(localThrowable);
    101     }
    102   }
    103   
    104   static
    105   {
    106     try
    107     {
    108       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
    109       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    110       m3 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getName", new Class[] { Integer.TYPE });
    111       m4 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getAge", new Class[] { Integer.TYPE });
    112       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    113       return;
    114     }
    115     catch (NoSuchMethodException localNoSuchMethodException)
    116     {
    117       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    118     }
    119     catch (ClassNotFoundException localClassNotFoundException)
    120     {
    121       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    122     }
    123   }
    124 }
    proxy0

    proxy0分析分两部份

    1.在内存动态生成代理类 以$proxy 开头

    $Proxy0 extends Proxy implements XXXXProxy.UserService

    并初始化InvocationHandler 同绑定 Method

     1 public $Proxy0(InvocationHandler paramInvocationHandler)
     2 {
     3   super(paramInvocationHandler);
     4 }
     5 
     6 static
     7 {
     8 try
     9 {
    10   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
    11   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    12   m3 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getName", new Class[] { Integer.TYPE });
    13   m4 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getAge", new Class[] { Integer.TYPE });
    14   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    15   return;
    16 }
    17 .....
    18 }

    第二部分:代理原对象所有方法实现调用InvocationHandler 类的 Object invoke(Object target, Method method, Object[] args) throws Throwable 方法 再通过method反射invoke

    public final String getName(int paramInt)
    {
    try
    {
        return (String)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
    }
    catch (Error|RuntimeException localError)
    {
        throw localError;
    }
    catch (Throwable localThrowable)
    {
        throw new UndeclaredThrowableException(localThrowable);
    }
    }

    我们通过生成指令 E:javafindmecomsunproxy>javap -v $Proxy0.class > d.txt

    来查看代理过的getName方法共多少条指令

      public final java.lang.String getName(int) throws ;
        descriptor: (I)Ljava/lang/String;
        flags: ACC_PUBLIC, ACC_FINAL
        Code:
          stack=10, locals=3, args_size=2
             0: aload_0
             1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
             4: aload_0
             5: getstatic     #57                 // Field m3:Ljava/lang/reflect/Method;
             8: iconst_1
             9: anewarray     #22                 // class java/lang/Object
            12: dup
            13: iconst_0
            14: iload_1
            15: invokestatic  #63                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            18: aastore
            19: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
            24: checkcast     #52                 // class java/lang/String
            27: areturn
            28: athrow
            29: astore_2
            30: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
            33: dup
            34: aload_2
            35: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
            38: athrow
          Exception table:
             from    to  target type
                 0    28    28   Class java/lang/Error
                 0    28    28   Class java/lang/RuntimeException
                 0    28    29   Class java/lang/Throwable
        Exceptions:
          throws

    如果不出错,到 27:areturn  至少要执行到13条指令 java8对动态代理有优化过

    结论是:jdk动态代理比原生调用只慢几十毫秒,这点可以忽略不计

  • 相关阅读:
    🔺 Garbage Remembering Exam UVA
    Cows and Cars UVA
    Probability|Given UVA
    Crossing Rivers HDU
    均匀分布和高斯分布
    Race to 1 UVA
    XMPPElementReceipt wait return,
    someone like you,
    第三方统计,
    截获的感觉,
  • 原文地址:https://www.cnblogs.com/solq111/p/6627322.html
Copyright © 2020-2023  润新知