深挖JDK动态代理:JDK动态生成后的字节码分析
Posted lonecloud
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深挖JDK动态代理:JDK动态生成后的字节码分析相关的知识,希望对你有一定的参考价值。
接上一篇文章深挖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
总结: 代理对象生成类:
1. 该代理对象会将该接口的的方法进行一次封装通过调用super.h.invoke(this, m0, (Object[])null);将执行之前定义的InvolicationHandler类中的invoke方法然后再调用我们之前编写的类方法。
2. 会将Object类中的toString,equals,hashCode这些方法进行代理
3. 将InvocationHandler通过成员变量的形式传递到类中
以上是关于深挖JDK动态代理:JDK动态生成后的字节码分析的主要内容,如果未能解决你的问题,请参考以下文章