深挖JDK動態代理(二):JDK動態生成後的位元組碼分析

lonecloud發表於2018-06-09

接上一篇文章深挖JDK動態代理(一)我們來分析一下JDK生成動態的代理類究竟是個什麼東西

1. 將生成的代理類程式設計一個class檔案,通過以下方法

    public static void transClass() throws IOException {
        URL resource = rpcMain.class.getClass().getResource("/");
        byte[] bts = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{HelloService.class});
        File file = new File(resource.getPath(),"$Proxy0.class");
        if (!file.exists()){
            file.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(bts);
        fos.flush();
        fos.close();
        System.out.println(resource.getPath());
    }

  主要是通過ProxyGenerator.generateProxyClass獲取代理類,該方法第一個為生成該類的名字,可以通過DEBUG的形式獲取,第二個引數為該動態代理類所實現的介面,然後獲取其位元組碼檔案,將該位元組碼檔案寫入到檔案中

2. 通過JD-GUI反編譯程式碼

import cn.lonecloud.study.dto.HelloDto;
import cn.lonecloud.study.service.HelloService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//該類整合了Proxy代理類,和實現了HelloService介面
public final class $Proxy0 extends Proxy implements HelloService {
    //宣告瞭一系列方法,為啥要宣告這個呢?請看最後面的實現類
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    //重寫Object類中equals方法
    public final boolean equals(Object var1) throws  {
        try {
            //都通過代理形式呼叫
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    //實現getHello方法,通過代理形式
    public final HelloDto getHello(String var1) throws  {
        try {
            return (HelloDto)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
   //重寫toString方法
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    //重寫hashCode方法
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    //類初始化
    static {
        try {
            //載入Object類,並獲取其equals方法
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
           //載入HelloService介面,並獲取其getHello方法
            m3 = Class.forName("cn.lonecloud.study.service.HelloService").getMethod("getHello", Class.forName("java.lang.String"));
            //載入Object類,並獲取其toString方法
            m2 = Class.forName("java.lang.Object").getMethod("toString");
             //載入Object類,並獲取其hashCode方法          
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
                

  

3. 將位元組碼通過 javap -verbose \$Proxy0來獲取位元組碼

Classfile /Users/lonecloud/Documents/ideaCode/target/classes/$Proxy0.class
  Last modified 2018-6-9; size 2076 bytes
  MD5 checksum a9c607b2d44135c7672b37458cc16c23
public final class $Proxy0 extends java.lang.reflect.Proxy implements cn.lonecloud.study.service.HelloService
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
    #1 = Utf8               <init>
    #2 = Utf8               (Ljava/lang/reflect/InvocationHandler;)V
    #3 = Utf8               Code
    #4 = Utf8               Exceptions
    #5 = Utf8               java/lang/reflect/Proxy
    #6 = Class              #5            // java/lang/reflect/Proxy
    #7 = NameAndType        #1:#2         // "<init>":(Ljava/lang/reflect/InvocationHandler;)V
    #8 = Methodref          #6.#7         // java/lang/reflect/Proxy."<init>":(Ljava/lang/reflect/InvocationHandler;)V
    #9 = Utf8               m1
   #10 = Utf8               Ljava/lang/reflect/Method;
   #11 = Utf8               equals
   #12 = Utf8               (Ljava/lang/Object;)Z
   #13 = Utf8               h
   #14 = Utf8               Ljava/lang/reflect/InvocationHandler;
   #15 = NameAndType        #13:#14       // h:Ljava/lang/reflect/InvocationHandler;
   #16 = Fieldref           #6.#15        // java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
   #17 = Utf8               $Proxy0
   #18 = Class              #17           // $Proxy0
   #19 = NameAndType        #9:#10        // m1:Ljava/lang/reflect/Method;
   #20 = Fieldref           #18.#19       // $Proxy0.m1:Ljava/lang/reflect/Method;
   #21 = Utf8               java/lang/Object
   #22 = Class              #21           // java/lang/Object
   #23 = Utf8               java/lang/reflect/InvocationHandler
   #24 = Class              #23           // java/lang/reflect/InvocationHandler
   #25 = Utf8               invoke
   #26 = Utf8               (Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
   #27 = NameAndType        #25:#26       // invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
   #28 = InterfaceMethodref #24.#27       // java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
   #29 = Utf8               java/lang/Boolean
   #30 = Class              #29           // java/lang/Boolean
   #31 = Utf8               booleanValue
   #32 = Utf8               ()Z
   #33 = NameAndType        #31:#32       // booleanValue:()Z
   #34 = Methodref          #30.#33       // java/lang/Boolean.booleanValue:()Z
   #35 = Utf8               java/lang/Error
   #36 = Class              #35           // java/lang/Error
   #37 = Utf8               java/lang/RuntimeException
   #38 = Class              #37           // java/lang/RuntimeException
   #39 = Utf8               java/lang/Throwable
   #40 = Class              #39           // java/lang/Throwable
   #41 = Utf8               java/lang/reflect/UndeclaredThrowableException
   #42 = Class              #41           // java/lang/reflect/UndeclaredThrowableException
   #43 = Utf8               (Ljava/lang/Throwable;)V
   #44 = NameAndType        #1:#43        // "<init>":(Ljava/lang/Throwable;)V
   #45 = Methodref          #42.#44       // java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
   #46 = Utf8               m3
   #47 = Utf8               getHello
   #48 = Utf8               (Ljava/lang/String;)Lcn/lonecloud/study/dto/HelloDto;
   #49 = NameAndType        #46:#10       // m3:Ljava/lang/reflect/Method;
   #50 = Fieldref           #18.#49       // $Proxy0.m3:Ljava/lang/reflect/Method;
   #51 = Utf8               cn/lonecloud/study/dto/HelloDto
   #52 = Class              #51           // cn/lonecloud/study/dto/HelloDto
   #53 = Utf8               m2
   #54 = Utf8               toString
   #55 = Utf8               ()Ljava/lang/String;
   #56 = NameAndType        #53:#10       // m2:Ljava/lang/reflect/Method;
   #57 = Fieldref           #18.#56       // $Proxy0.m2:Ljava/lang/reflect/Method;
   #58 = Utf8               java/lang/String
   #59 = Class              #58           // java/lang/String
   #60 = Utf8               m0
   #61 = Utf8               hashCode
   #62 = Utf8               ()I
   #63 = NameAndType        #60:#10       // m0:Ljava/lang/reflect/Method;
   #64 = Fieldref           #18.#63       // $Proxy0.m0:Ljava/lang/reflect/Method;
   #65 = Utf8               java/lang/Integer
   #66 = Class              #65           // java/lang/Integer
   #67 = Utf8               intValue
   #68 = NameAndType        #67:#62       // intValue:()I
   #69 = Methodref          #66.#68       // java/lang/Integer.intValue:()I
   #70 = Utf8               <clinit>
   #71 = Utf8               ()V
   #72 = Utf8               java.lang.Object
   #73 = String             #72           // java.lang.Object
   #74 = Utf8               java/lang/Class
   #75 = Class              #74           // java/lang/Class
   #76 = Utf8               forName
   #77 = Utf8               (Ljava/lang/String;)Ljava/lang/Class;
   #78 = NameAndType        #76:#77       // forName:(Ljava/lang/String;)Ljava/lang/Class;
   #79 = Methodref          #75.#78       // java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
   #80 = String             #11           // equals
   #81 = Utf8               getMethod
   #82 = Utf8               (Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #83 = NameAndType        #81:#82       // getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #84 = Methodref          #75.#83       // java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #85 = Utf8               cn.lonecloud.study.service.HelloService
   #86 = String             #85           // cn.lonecloud.study.service.HelloService
   #87 = String             #47           // getHello
   #88 = Utf8               java.lang.String
   #89 = String             #88           // java.lang.String
   #90 = String             #54           // toString
   #91 = String             #61           // hashCode
   #92 = Utf8               java/lang/NoSuchMethodException
   #93 = Class              #92           // java/lang/NoSuchMethodException
   #94 = Utf8               java/lang/NoSuchMethodError
   #95 = Class              #94           // java/lang/NoSuchMethodError
   #96 = Utf8               getMessage
   #97 = NameAndType        #96:#55       // getMessage:()Ljava/lang/String;
   #98 = Methodref          #40.#97       // java/lang/Throwable.getMessage:()Ljava/lang/String;
   #99 = Utf8               (Ljava/lang/String;)V
  #100 = NameAndType        #1:#99        // "<init>":(Ljava/lang/String;)V
  #101 = Methodref          #95.#100      // java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
  #102 = Utf8               java/lang/ClassNotFoundException
  #103 = Class              #102          // java/lang/ClassNotFoundException
  #104 = Utf8               java/lang/NoClassDefFoundError
  #105 = Class              #104          // java/lang/NoClassDefFoundError
  #106 = Methodref          #105.#100     // java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
  #107 = Utf8               cn/lonecloud/study/service/HelloService
  #108 = Class              #107          // cn/lonecloud/study/service/HelloService
{
  public $Proxy0(java.lang.reflect.InvocationHandler) throws ;
    descriptor: (Ljava/lang/reflect/InvocationHandler;)V
    flags: ACC_PUBLIC
    Code:
      stack=10, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: invokespecial #8                  // Method java/lang/reflect/Proxy."<init>":(Ljava/lang/reflect/InvocationHandler;)V
         5: return
    Exceptions:
      throws

  public final boolean equals(java.lang.Object) throws ;
    descriptor: (Ljava/lang/Object;)Z
    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     #20                 // Field m1:Ljava/lang/reflect/Method;
         8: iconst_1
         9: anewarray     #22                 // class java/lang/Object
        12: dup
        13: iconst_0
        14: aload_1
        15: aastore
        16: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
        21: checkcast     #30                 // class java/lang/Boolean
        24: invokevirtual #34                 // Method java/lang/Boolean.booleanValue:()Z
        27: ireturn
        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

  public final cn.lonecloud.study.dto.HelloDto getHello(java.lang.String) throws ;
    descriptor: (Ljava/lang/String;)Lcn/lonecloud/study/dto/HelloDto;
    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     #50                 // Field m3:Ljava/lang/reflect/Method;
         8: iconst_1
         9: anewarray     #22                 // class java/lang/Object
        12: dup
        13: iconst_0
        14: aload_1
        15: aastore
        16: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
        21: checkcast     #52                 // class cn/lonecloud/study/dto/HelloDto
        24: areturn
        25: athrow
        26: astore_2
        27: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
        30: dup
        31: aload_2
        32: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        35: athrow
      Exception table:
         from    to  target type
             0    25    25   Class java/lang/Error
             0    25    25   Class java/lang/RuntimeException
             0    25    26   Class java/lang/Throwable
    Exceptions:
      throws

  public final java.lang.String toString() throws ;
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=10, locals=2, args_size=1
         0: aload_0
         1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
         4: aload_0
         5: getstatic     #57                 // Field m2:Ljava/lang/reflect/Method;
         8: aconst_null
         9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
        14: checkcast     #59                 // class java/lang/String
        17: areturn
        18: athrow
        19: astore_1
        20: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
        23: dup
        24: aload_1
        25: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        28: athrow
      Exception table:
         from    to  target type
             0    18    18   Class java/lang/Error
             0    18    18   Class java/lang/RuntimeException
             0    18    19   Class java/lang/Throwable
    Exceptions:
      throws

  public final int hashCode() throws ;
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=10, locals=2, args_size=1
         0: aload_0
         1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
         4: aload_0
         5: getstatic     #64                 // Field m0:Ljava/lang/reflect/Method;
         8: aconst_null
         9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
        14: checkcast     #66                 // class java/lang/Integer
        17: invokevirtual #69                 // Method java/lang/Integer.intValue:()I
        20: ireturn
        21: athrow
        22: astore_1
        23: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
        26: dup
        27: aload_1
        28: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        31: athrow
      Exception table:
         from    to  target type
             0    21    21   Class java/lang/Error
             0    21    21   Class java/lang/RuntimeException
             0    21    22   Class java/lang/Throwable
    Exceptions:
      throws

  static {} throws ;
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=10, locals=2, args_size=0
         0: ldc           #73                 // String java.lang.Object
         2: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
         5: ldc           #80                 // String equals
         7: iconst_1
         8: anewarray     #75                 // class java/lang/Class
        11: dup
        12: iconst_0
        13: ldc           #73                 // String java.lang.Object
        15: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        18: aastore
        19: invokevirtual #84                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        22: putstatic     #20                 // Field m1:Ljava/lang/reflect/Method;
        25: ldc           #86                 // String cn.lonecloud.study.service.HelloService
        27: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        30: ldc           #87                 // String getHello
        32: iconst_1
        33: anewarray     #75                 // class java/lang/Class
        36: dup
        37: iconst_0
        38: ldc           #89                 // String java.lang.String
        40: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        43: aastore
        44: invokevirtual #84                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        47: putstatic     #50                 // Field m3:Ljava/lang/reflect/Method;
        50: ldc           #73                 // String java.lang.Object
        52: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        55: ldc           #90                 // String toString
        57: iconst_0
        58: anewarray     #75                 // class java/lang/Class
        61: invokevirtual #84                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        64: putstatic     #57                 // Field m2:Ljava/lang/reflect/Method;
        67: ldc           #73                 // String java.lang.Object
        69: invokestatic  #79                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        72: ldc           #91                 // String hashCode
        74: iconst_0
        75: anewarray     #75                 // class java/lang/Class
        78: invokevirtual #84                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        81: putstatic     #64                 // Field m0:Ljava/lang/reflect/Method;
        84: return
        85: astore_1
        86: new           #95                 // class java/lang/NoSuchMethodError
        89: dup
        90: aload_1
        91: invokevirtual #98                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
        94: invokespecial #101                // Method java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
        97: athrow
        98: astore_1
        99: new           #105                // class java/lang/NoClassDefFoundError
       102: dup
       103: aload_1
       104: invokevirtual #98                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
       107: invokespecial #106                // Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
       110: athrow
      Exception table:
         from    to  target type
             0    85    85   Class java/lang/NoSuchMethodException
             0    85    98   Class java/lang/ClassNotFoundException
    Exceptions:
      throws
View Code

總結: 代理物件生成類:

1. 該代理物件會將該介面的的方法進行一次封裝通過呼叫super.h.invoke(this, m0, (Object[])null);將執行之前定義的InvolicationHandler類中的invoke方法然後再呼叫我們之前編寫的類方法。

2. 會將Object類中的toString,equals,hashCode這些方法進行代理

3. 將InvocationHandler通過成員變數的形式傳遞到類中

  

 

相關文章