JVM學習筆記17 動態代理運作機制

bilibili-JVM學習筆記17 動態代理運作機制
The Java Virtual Machine Specification - Java SE 8 Edition

JVM學習筆記11 - Java字節碼初識
JVM學習筆記12 - 解讀筆記11中的attributes
JVM學習筆記13
JVM學習筆記14 異常
JVM學習筆記15 方法執行
JVM學習筆記16 字節碼執行

透過字節碼生成審視Java動態代理運作機制

package new_package.jvm.p57;

public interface Subject {
    void request();
}
package new_package.jvm.p57;

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject request");
    }
}
package new_package.jvm.p57;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicSubject implements InvocationHandler {

    private Object subject;

    public DynamicSubject(Object object) {
        this.subject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before calling: " + method);
        method.invoke(this.subject, args);
        System.out.println("after calling: " + method);
        return proxy;
    }
}
package new_package.jvm.p57;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        Subject subject = new RealSubject();
        InvocationHandler handler = new DynamicSubject(subject);
        Subject proxy = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
        proxy.request();
        System.out.println(proxy.getClass());
        System.out.println(proxy.getClass().getSuperclass());
    }
}

java.lang.reflect.Proxy


    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class. (生成代理類的字節碼)
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

sun.misc.ProxyGenerator

    /**
     * Generate a proxy class given a name and a list of proxy interfaces.
     *
     * @param name        the class name of the proxy class
     * @param interfaces  proxy interfaces
     * @param accessFlags access flags of the proxy class
    */
    public static byte[] generateProxyClass(final String name,
                                            Class<?>[] interfaces,
                                            int accessFlags)
    {
        ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
        final byte[] classFile = gen.generateClassFile();

        if (saveGeneratedFiles) {
            java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int i = name.lastIndexOf('.');
                        Path path;
                        if (i > 0) {
                            Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
                            Files.createDirectories(dir);
                            path = dir.resolve(name.substring(i+1, name.length()) + ".class");
                        } else {
                            path = Paths.get(name + ".class");
                        }
                        Files.write(path, classFile);
                        return null;
                    } catch (IOException e) {
                        throw new InternalError(
                            "I/O exception saving generated file: " + e);
                    }
                }
            });
        }

        return classFile;
    }
    /**
     * Generate a class file for the proxy class.  This method drives the
     * class file generation process.
     */
    private byte[] generateClassFile() {

        /* ============================================================
         * Step 1: Assemble ProxyMethod objects for all methods to
         * generate proxy dispatching code for.
         */

        /*
         * Record that proxy methods are needed for the hashCode, equals,
         * and toString methods of java.lang.Object.  This is done before
         * the methods from the proxy interfaces so that the methods from
         * java.lang.Object take precedence over duplicate methods in the
         * proxy interfaces.
         */
        addProxyMethod(hashCodeMethod, Object.class);
        addProxyMethod(equalsMethod, Object.class);
        addProxyMethod(toStringMethod, Object.class);

        /*
         * Now record all of the methods from the proxy interfaces, giving
         * earlier interfaces precedence over later ones with duplicate
         * methods.
         */
        for (Class<?> intf : interfaces) {
            for (Method m : intf.getMethods()) {
                addProxyMethod(m, intf);
            }
        }

        /*
         * For each set of proxy methods with the same signature,
         * verify that the methods' return types are compatible.
         */
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            checkReturnTypes(sigmethods);
        }

        /* ============================================================
         * Step 2: Assemble FieldInfo and MethodInfo structs for all of
         * fields and methods in the class we are generating.
         */
        try {
            methods.add(generateConstructor());

            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
                for (ProxyMethod pm : sigmethods) {

                    // add static field for method's Method object
                    fields.add(new FieldInfo(pm.methodFieldName,
                        "Ljava/lang/reflect/Method;",
                         ACC_PRIVATE | ACC_STATIC));

                    // generate code for proxy method and add it
                    methods.add(pm.generateMethod());
                }
            }

            methods.add(generateStaticInitializer());

        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }

        if (methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        }
        if (fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        }

        /* ============================================================
         * Step 3: Write the final class file.
         */

        /*
         * Make sure that constant pool indexes are reserved for the
         * following items before starting to write the final class file.
         */
        cp.getClass(dotToSlash(className));
        cp.getClass(superclassName);
        for (Class<?> intf: interfaces) {
            cp.getClass(dotToSlash(intf.getName()));
        }

        /*
         * Disallow new constant pool additions beyond this point, since
         * we are about to write the final constant pool table.
         */
        cp.setReadOnly();

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
            /*
             * Write all the items of the "ClassFile" structure.
             * See JVMS section 4.1.
             */
                                        // u4 magic;
            dout.writeInt(0xCAFEBABE);
                                        // u2 minor_version;
            dout.writeShort(CLASSFILE_MINOR_VERSION);
                                        // u2 major_version;
            dout.writeShort(CLASSFILE_MAJOR_VERSION);

            cp.write(dout);             // (write constant pool)

                                        // u2 access_flags;
            dout.writeShort(accessFlags);
                                        // u2 this_class;
            dout.writeShort(cp.getClass(dotToSlash(className)));
                                        // u2 super_class;
            dout.writeShort(cp.getClass(superclassName));

                                        // u2 interfaces_count;
            dout.writeShort(interfaces.length);
                                        // u2 interfaces[interfaces_count];
            for (Class<?> intf : interfaces) {
                dout.writeShort(cp.getClass(
                    dotToSlash(intf.getName())));
            }

                                        // u2 fields_count;
            dout.writeShort(fields.size());
                                        // field_info fields[fields_count];
            for (FieldInfo f : fields) {
                f.write(dout);
            }

                                        // u2 methods_count;
            dout.writeShort(methods.size());
                                        // method_info methods[methods_count];
            for (MethodInfo m : methods) {
                m.write(dout);
            }

                                         // u2 attributes_count;
            dout.writeShort(0); // (no ClassFile attributes for proxy classes)

        } catch (IOException e) {
            throw new InternalError("unexpected I/O Exception", e);
        }

        return bout.toByteArray();
    }



sun.misc.ProxyGenerator.saveGeneratedFiles 系統變量設置爲 true

package new_package.jvm.p57;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {

        // debugging flag for saving generated class files
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

        Subject subject = new RealSubject();
        InvocationHandler handler = new DynamicSubject(subject);
        Subject proxy = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
        proxy.request();
        System.out.println(proxy.getClass());
        System.out.println(proxy.getClass().getSuperclass());
    }
}

在工程目錄下生成一個文件 com.sun.proxy.$Proxy0

在這裏插入圖片描述

javap -v com.sun.proxy.$Proxy0

Classfile /Users/kevin/Documents/opensource/gitee/java-read-sources-sample/com/sun/proxy/$Proxy0.class
  Last modified 2020-6-13; size 1933 bytes
  MD5 checksum 8b7db9cc13cf98eeeff555cb57c49163
public final class com.sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implements new_package.jvm.p57.Subject
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_FINAL
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               com/sun/proxy/$Proxy0
   #18 = Class              #17           // com/sun/proxy/$Proxy0
   #19 = NameAndType        #9:#10        // m1:Ljava/lang/reflect/Method;
   #20 = Fieldref           #18.#19       // com/sun/proxy/$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               m2
   #47 = Utf8               toString
   #48 = Utf8               ()Ljava/lang/String;
   #49 = NameAndType        #46:#10       // m2:Ljava/lang/reflect/Method;
   #50 = Fieldref           #18.#49       // com/sun/proxy/$Proxy0.m2:Ljava/lang/reflect/Method;
   #51 = Utf8               java/lang/String
   #52 = Class              #51           // java/lang/String
   #53 = Utf8               m3
   #54 = Utf8               request
   #55 = Utf8               ()V
   #56 = NameAndType        #53:#10       // m3:Ljava/lang/reflect/Method;
   #57 = Fieldref           #18.#56       // com/sun/proxy/$Proxy0.m3:Ljava/lang/reflect/Method;
   #58 = Utf8               m0
   #59 = Utf8               hashCode
   #60 = Utf8               ()I
   #61 = NameAndType        #58:#10       // m0:Ljava/lang/reflect/Method;
   #62 = Fieldref           #18.#61       // com/sun/proxy/$Proxy0.m0:Ljava/lang/reflect/Method;
   #63 = Utf8               java/lang/Integer
   #64 = Class              #63           // java/lang/Integer
   #65 = Utf8               intValue
   #66 = NameAndType        #65:#60       // intValue:()I
   #67 = Methodref          #64.#66       // java/lang/Integer.intValue:()I
   #68 = Utf8               <clinit>
   #69 = Utf8               java.lang.Object
   #70 = String             #69           // java.lang.Object
   #71 = Utf8               java/lang/Class
   #72 = Class              #71           // java/lang/Class
   #73 = Utf8               forName
   #74 = Utf8               (Ljava/lang/String;)Ljava/lang/Class;
   #75 = NameAndType        #73:#74       // forName:(Ljava/lang/String;)Ljava/lang/Class;
   #76 = Methodref          #72.#75       // java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
   #77 = String             #11           // equals
   #78 = Utf8               getMethod
   #79 = Utf8               (Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #80 = NameAndType        #78:#79       // getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #81 = Methodref          #72.#80       // java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   #82 = String             #47           // toString
   #83 = Utf8               new_package.jvm.p57.Subject
   #84 = String             #83           // new_package.jvm.p57.Subject
   #85 = String             #54           // request
   #86 = String             #59           // hashCode
   #87 = Utf8               java/lang/NoSuchMethodException
   #88 = Class              #87           // java/lang/NoSuchMethodException
   #89 = Utf8               java/lang/NoSuchMethodError
   #90 = Class              #89           // java/lang/NoSuchMethodError
   #91 = Utf8               getMessage
   #92 = NameAndType        #91:#48       // getMessage:()Ljava/lang/String;
   #93 = Methodref          #40.#92       // java/lang/Throwable.getMessage:()Ljava/lang/String;
   #94 = Utf8               (Ljava/lang/String;)V
   #95 = NameAndType        #1:#94        // "<init>":(Ljava/lang/String;)V
   #96 = Methodref          #90.#95       // java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
   #97 = Utf8               java/lang/ClassNotFoundException
   #98 = Class              #97           // java/lang/ClassNotFoundException
   #99 = Utf8               java/lang/NoClassDefFoundError
  #100 = Class              #99           // java/lang/NoClassDefFoundError
  #101 = Methodref          #100.#95      // java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
  #102 = Utf8               new_package/jvm/p57/Subject
  #103 = Class              #102          // new_package/jvm/p57/Subject
{
  public com.sun.proxy.$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 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     #50                 // 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     #52                 // 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 void request() throws ;
    descriptor: ()V
    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 m3: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: pop
        15: return
        16: athrow
        17: astore_1
        18: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
        21: dup
        22: aload_1
        23: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        26: athrow
      Exception table:
         from    to  target type
             0    16    16   Class java/lang/Error
             0    16    16   Class java/lang/RuntimeException
             0    16    17   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     #62                 // 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     #64                 // class java/lang/Integer
        17: invokevirtual #67                 // 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           #70                 // String java.lang.Object
         2: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
         5: ldc           #77                 // String equals
         7: iconst_1
         8: anewarray     #72                 // class java/lang/Class
        11: dup
        12: iconst_0
        13: ldc           #70                 // String java.lang.Object
        15: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        18: aastore
        19: invokevirtual #81                 // 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           #70                 // String java.lang.Object
        27: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        30: ldc           #82                 // String toString
        32: iconst_0
        33: anewarray     #72                 // class java/lang/Class
        36: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        39: putstatic     #50                 // Field m2:Ljava/lang/reflect/Method;
        42: ldc           #84                 // String new_package.jvm.p57.Subject
        44: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        47: ldc           #85                 // String request
        49: iconst_0
        50: anewarray     #72                 // class java/lang/Class
        53: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        56: putstatic     #57                 // Field m3:Ljava/lang/reflect/Method;
        59: ldc           #70                 // String java.lang.Object
        61: invokestatic  #76                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
        64: ldc           #86                 // String hashCode
        66: iconst_0
        67: anewarray     #72                 // class java/lang/Class
        70: invokevirtual #81                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
        73: putstatic     #62                 // Field m0:Ljava/lang/reflect/Method;
        76: return
        77: astore_1
        78: new           #90                 // class java/lang/NoSuchMethodError
        81: dup
        82: aload_1
        83: invokevirtual #93                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
        86: invokespecial #96                 // Method java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
        89: athrow
        90: astore_1
        91: new           #100                // class java/lang/NoClassDefFoundError
        94: dup
        95: aload_1
        96: invokevirtual #93                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
        99: invokespecial #101                // Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
       102: athrow
      Exception table:
         from    to  target type
             0    77    77   Class java/lang/NoSuchMethodException
             0    77    90   Class java/lang/ClassNotFoundException
    Exceptions:
      throws
}

動態代理實現機制深層次分析與動態字節碼生成總結

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import new_package.jvm.p57.Subject;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    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);
        }
    }

    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);
        }
    }

    public final void request() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("new_package.jvm.p57.Subject").getMethod("request");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

動態代理

  • java Proxy
    • 必須是接口
    • 生成代理類(extends Proxy implements XXX ),實現 InvocationHadler 接口,添加自己的業務邏輯
  • cglib
    • 非 final class
    • 動態生成一個子類繼承該類,然後重新父類方法,添加自己的業務邏輯
  • javassist
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章