手寫JDK動態代理

JDK動態代理原理:

  1. 拿到被代理對象的引用,然後獲取它的接口
  2. JDK代理重新生成一個類,同時實現我們給的代理對象所實現的接口
  3. 把被代理對象的引用也拿到了
  4. 重新動態生成一個class字節碼
  5. 然後編譯

1. 獲取動態生成的class文件

我們知道了JDK動態代理是動態生成java代碼,然後編譯、加載、執行實現的。我們如何看看JDK自動生成的java文件是怎樣的呢?可以通過以下代碼獲取動態class文件:

byte[] data = ProxyGenerator.generateProxyClass("$Proxy00", new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("$Proxy00.class");
os.write(data);
os.close();

得到 $Proxy00.class 文件
 $Proxy00.class 文件

2. 反編譯 $Proxy00.class 文件

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

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.jdk.Person;

public final class $Proxy00 extends Proxy implements Person {
    private static Method m1;
    private static Method m4;
    private static Method m3;
    private static Method m5;
    private static Method m2;
    private static Method m0;

    public $Proxy00(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 getSex() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

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

    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 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"));
            m4 = Class.forName("proxy.jdk.Person").getMethod("getSex");
            m3 = Class.forName("proxy.jdk.Person").getMethod("getName");
            m5 = Class.forName("proxy.jdk.Person").getMethod("findLove");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

查看發現動態類繼承了 Proxy 實現了代理接口 Person

3. 查看 Proxy

Proxy類就是用來創建一個代理對象的類

這個類主要功能:

  1. 生成源代碼
  2. 將生成的代碼輸出到磁盤,保存爲.java文件
  3. 編譯爲.class文件
  4. 加載.class文件內容到JVM
  5. 返回被代理對象

去除private方法,把主要參數和方法標識一下,也就是我們需要自己去寫的東西。

package java.lang.reflect;

import ...;

public class Proxy implements java.io.Serializable {

    ...
    
    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    // 主要參數,這是一個接口
    // 這個參數相當於一個標識
    
    // 這裏運用了一個設計模式
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }
    
    // 主要構造方法
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
        throws IllegalArgumentException
    {
      ...
    }

	// 主要方法
	// ClassLoader 也自己實現
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
        
       ...
       
    }

    public static boolean isProxyClass(Class<?> cl) {
        return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

    public static InvocationHandler getInvocationHandler(Object proxy)
        throws IllegalArgumentException
    {
       ...
    }
}

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException這個方法的作用就是創建一個代理類對象,它接收三個參數,我們來看下幾個參數的含義:

  • loader:一個classloader對象,定義了由哪個classloader對象對生成的代理類進行加載
  • interfaces:一個interface對象數組, 表示我們將要給我們的代理對象提供一組什麼樣的接口,如果我們提供了這樣一個接口對象數組,那麼也就是聲明瞭代理類實現了這些接口,代理類就可以調用接口中聲明的所有方法。
  • h:一個InvocationHandler對象,表示的是當動態代理對象調用方法的時候會關聯到哪一個InvocationHandler對象上,並最終由其調用。

4. 查看 InvocationHandler 接口

就一個Object invoke(Object proxy, Method method, Object[] args) throws Throwable;方法

package java.lang.reflect;

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

InvocationHandler類的主要功能:

  • InvocationHandler接口是proxy代理實例的調用處理程序實現的一個接口,每一個proxy代理實例都有一個關聯的調用處理程序;在代理實例調用方法時,方法調用被編碼分派到調用處理程序的invoke方法。

5. 自己寫一個 InvocationHandler

無非就該個名字了

GMInvocationHandler.java

    package proxy.self;
    
    import java.lang.reflect.Method;
    
    /**
     * 代理接口
     *
     * @author 周廣明
     * @version v1 2020/2/16 9:52
     */
    public interface GMInvocationHandler {
    
        Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable;
    }

6. 自己寫一個 ClassLoader

ClassLoader 功能:

  • 把類加載到JVM

爲啥要自己寫,因爲自己生成的class文件需要自己指定去加載。

GMClassLoader.java

package proxy.self;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 重新將class文件動態load到JVM
 *
 * @author 周廣明
 * @version v1 2020/2/16 9:55
 */
public class GMClassLoader extends ClassLoader {

    // 類目錄
    private File baseDir;

    public GMClassLoader() {
        this.baseDir = new File("D:\\IdeaProjects\\code\\src\\");
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String className = GMClassLoader.class.getPackage().getName() + "." + name;

        if (baseDir != null) {
            // 自己生成的類文件
            File classFile = new File(baseDir, className.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();

                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (in != null) {
                            in.close();
                        }
                        if (out != null) {
                            out.close();
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    // 刪除臨時文件
                    classFile.delete();
                }

            } else {
                throw new ClassNotFoundException("未找到類文件");
            }
        } else {
            throw new ClassNotFoundException("類目錄錯誤");
        }

        return null;
    }
}

7. 自己寫一個 Proxy

需要實現上面分析的主要方法

1. 方法 generateSrc(Class<?>[] interfaces):生成源代碼

private static String generateSrc(Class<?>[] interfaces) {
		// 換行
        String ln = "\r\n";

        StringBuilder proxySrc = new StringBuilder();
        // 0引入包名
        proxySrc.append("package proxy.self;").append(ln);
        // 1引入類
        proxySrc.append("import proxy.self.GMInvocationHandler;").append(ln);
        proxySrc.append("import proxy.self.GMProxy;").append(ln);
        proxySrc.append("import java.lang.reflect.Method;").append(ln);
        proxySrc.append("import java.lang.reflect.UndeclaredThrowableException;").append(ln);
        // 1.1引入代理接口類
        for (Class<?> interfaceClass : interfaces) {
            proxySrc.append("import ").append(interfaceClass.getName()).append(";").append(ln);
        }
        // 2類名($GMProxy0)、繼承(自己的Proxy,GMProxy )及實現類,類開始
        proxySrc.append("public final class $GMProxy0 extends GMProxy implements ")
                // 實現的接口
                .append(getInterfacesStr(interfaces)).append(" {");
               
        // ##### 參數 ##### 
        
        // 3靜態方法參數
        // 三個 Object 默認方法
        // 3.1hashCode
        proxySrc.append("\nprivate static Method m0;").append(ln);
        // 3.2equals
        proxySrc.append("private static Method m1;").append(ln);
        // 3.3toString
        proxySrc.append("private static Method m2;").append(ln);
        // 3.4獲取實現類的方法
        // getMethodsThatImplements(Class<?>[] interfaces) 獲取接口的方法
        // getImplementAndMethodsStr(Map<String, Method[]> implementAndMethods) 獲取接口的方法的拼接字符串
        proxySrc.append(getImplementAndMethodsStr(getMethodsThatImplements(interfaces))).append(ln);
        
        // ##### 方法 #####
        
         // 4構造方法
        proxySrc.append("public $GMProxy0(GMInvocationHandler h) { super(h); }").append(ln);
        
        // 5拷貝hashCode m0
        proxySrc.append("public final int hashCode() {\n" +
                "        try {\n" +
                "            return (Integer)super.h.invoke(this, m0, null);\n" +
                "        } catch (RuntimeException | Error var2) {\n" +
                "            throw var2;\n" +
                "        } catch (Throwable var3) {\n" +
                "            throw new UndeclaredThrowableException(var3);\n" +
                "        }\n" +
                "    }").append(ln);

        // 6拷貝equals m1
        proxySrc.append(" public final boolean equals(Object var1) {\n" +
                "        try {\n" +
                "            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});\n" +
                "        } catch (RuntimeException | Error var3) {\n" +
                "            throw var3;\n" +
                "        } catch (Throwable var4) {\n" +
                "            throw new UndeclaredThrowableException(var4);\n" +
                "        }\n" +
                "    }").append(ln);

        // 7拷貝toString m2
        proxySrc.append("public final String toString() {" +
                "try {\n" +
                "            return (String)super.h.invoke(this, m2, null);\n" +
                "        } catch (RuntimeException | Error var2) {\n" +
                "            throw var2;\n" +
                "        } catch (Throwable var3) {\n" +
                "            throw new UndeclaredThrowableException(var3);\n" +
                "        }" +
                "}").append(ln);
                
		// 8代理接口的方法
		// getMethodsImplementStr(Map<String, Method[]> implementAndMethods) 代理方法的實現,字符串
        proxySrc.append(getMethodsImplementStr(getMethodsThatImplements(interfaces)));
        // 9靜態方法參數賦值
        // 前三個注意順序
        proxySrc.append("static {\n" +
                "        try {\n" +
                "            m0 = Class.forName(\"java.lang.Object\").getMethod(\"hashCode\");\n" +
                "            m1 = Class.forName(\"java.lang.Object\").getMethod(\"equals\", Class.forName(\"java.lang.Object\"));\n" +
                "            m2 = Class.forName(\"java.lang.Object\").getMethod(\"toString\");\n")
                // getStaticMethodValue(Map<String, Method[]> implementAndMethods) 獲取調用方法,字符串
                .append(getStaticMethodValue(getMethodsThatImplements(interfaces)))
                .append("} catch (NoSuchMethodException var2) {\n")
                .append("            throw new NoSuchMethodError(var2.getMessage());\n")
                .append("        } catch (ClassNotFoundException var3) {\n")
                .append("            throw new NoClassDefFoundError(var3.getMessage());\n")
                .append("        }\n")
                .append("    }");

		// 類結束
        proxySrc.append("}");
        
        return proxySrc.toString();
}

1.1 方法 getInterfacesStr(Class<?>[] interfaces)

拼接實現接口 public final class $Proxy00 extends Proxy implements xxxx {

	/**
     * 獲取實現接口的字符串
     *
     * @param interfaces
     * @return
     */
    private static String getInterfacesStr(Class<?>[] interfaces) {
        String ln = ",";
        StringBuilder interfaceNames = new StringBuilder();
        for (Class<?> interfaceClass : interfaces) {
            interfaceNames.append(interfaceClass.getSimpleName()).append(ln);
        }
        String interfacesStr = interfaceNames.toString();
        return interfacesStr.substring(0, interfacesStr.length() - 1);
    }

1.2 方法 getMethodsThatImplements(Class<?>[] interfaces)

獲取代理接口中的方法,返回Map,key=接口,value=方法數組

    /**
     * 獲取接口的方法
     *
     * @return Map
     */
    private static Map<String, Method[]> getMethodsThatImplements(Class<?>[] interfaces) {
        Map<String, Method[]> implementAndMethods = new HashMap<>();

        for (Class<?> anInterface : interfaces) {
            implementAndMethods.put(anInterface.getName(), anInterface.getMethods());
        }
        return implementAndMethods;
    }

1.3 方法 getImplementAndMethodsStr(Map<String, Method[]> implementAndMethods)

獲取接口的方法的靜態方法參數拼接字符串,如:private static Method m1;

    /**
     * 獲取接口的方法的拼接字符串
     *
     * @param implementAndMethods
     * @return
     */
    private static String getImplementAndMethodsStr(Map<String, Method[]> implementAndMethods) {
        StringBuilder interfaceNames = new StringBuilder();

        for (String key : implementAndMethods.keySet()) {
            Method[] methods = implementAndMethods.get(key);
            for (Method method : methods) {
                interfaceNames.append("private static Method ").append(method.getName()).append(";").append("\r\n");
            }
        }

        return interfaceNames.toString();
    }

1.4 方法 getMethodsImplementStr(Map<String, Method[]> implementAndMethods)

獲取代理方法的實現的字符串,標準如下:

public final [返回類型 方法名() | 方法名(參數...)] throws  {
        try {
            return (返回類型)super.h.invoke(this, m3, [(Object[])null | Object[] 參數]);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

未實現帶參方法

  /**
     * 代理方法的實現,字符串
     *
     * @param implementAndMethods
     * @return
     */
    private static String getMethodsImplementStr(Map<String, Method[]> implementAndMethods) {
        StringBuilder methodsImplement = new StringBuilder();
        for (String key : implementAndMethods.keySet()) {
            Method[] methods = implementAndMethods.get(key);
            for (Method method : methods) {
                Class<?> returnType = method.getReturnType();
                String returnTypeName = returnType.getName();
                String methodName = method.getName();
                // 判斷 void
                if (returnTypeName.equals("void")) {
                    methodsImplement
                            .append("public final void ").append(methodName).append("() {\n")
                            .append("        try {\n")
                            .append("            super.h.invoke(this, ").append(methodName).append(", null);\n")
                            .append("        } catch (RuntimeException | Error var2) {\n")
                            .append("            throw var2;\n")
                            .append("        } catch (Throwable var3) {\n")
                            .append("            throw new UndeclaredThrowableException(var3);\n")
                            .append("        }\n")
                            .append("    }").append("\r\n");
                } else {
                    methodsImplement
                            .append("public final ").append(returnTypeName).append(" ").append(methodName).append("() {\n")
                            .append("        try {\n")
                            .append("            return (").append(returnTypeName)
                            .append(")super.h.invoke(this, ")
                            .append(methodName)
                            .append(", null);\n")
                            .append("        } catch (RuntimeException | Error var2) {\n")
                            .append("            throw var2;\n").append("        } catch (Throwable var3) {\n")
                            .append("            throw new UndeclaredThrowableException(var3);\n")
                            .append("        }\n")
                            .append("    }").append("\r\n");
                }
            }
        }
        return methodsImplement.toString();
    }

2. 將生成的代碼輸出到磁盤,保存爲.java文件

String path = "D:\\IdeaProjects\\code\\src\\proxy\\self\\";
File f = new File(path + "$GMProxy0.java");

            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();

3. 編譯爲.class文件

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> fileObjects = manager.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, fileObjects);
            task.call();
            manager.close();

4. 加載.class文件內容到JVM

// 4加載.class文件內容到JVM
            Class<?> proxyClass = loader.findClass("$GMProxy0");

5. 返回被代理對象

// 5返回被代理對象
            Constructor<?> c = proxyClass.getConstructor(GMInvocationHandler.class);
            return c.newInstance(h);

6. 完整代碼

GMProxy.java

package proxy.self;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 生成代理對象的代碼
 *
 * @author 周廣明
 * @version v1 2020/2/16 9:54
 */
public class GMProxy {

    protected GMInvocationHandler h;

    public GMProxy(GMInvocationHandler h) {
        this.h = h;
    }

    public static Object newProxyInstance(
            GMClassLoader loader, Class<?>[] interfaces, GMInvocationHandler h) {
        try {
            // 1生成源代碼
            String proxySrc = generateSrc(interfaces);

            // 2將生成的代碼輸出到磁盤,保存爲.java文件
            String path = "D:\\IdeaProjects\\code\\src\\proxy\\self\\";
            File f = new File(path + "$GMProxy0.java");

            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();

            // 3編譯爲.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> fileObjects = manager.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, fileObjects);
            task.call();
            manager.close();

            // 刪除臨時文件
            f.delete();

            // 4加載.class文件內容到JVM
            Class<?> proxyClass = loader.findClass("$GMProxy0");

            // 5返回被代理對象
            Constructor<?> c = proxyClass.getConstructor(GMInvocationHandler.class);
            return c.newInstance(h);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 生成源代碼
     *
     * @param interfaces
     * @return
     */
    private static String generateSrc(Class<?>[] interfaces) {

        String ln = "\r\n";

        StringBuilder proxySrc = new StringBuilder();
        proxySrc.append("package proxy.self;").append(ln);

        // 1引入類
        proxySrc.append("import proxy.self.GMInvocationHandler;").append(ln);
        proxySrc.append("import proxy.self.GMProxy;").append(ln);
        proxySrc.append("import java.lang.reflect.Method;").append(ln);
        proxySrc.append("import java.lang.reflect.UndeclaredThrowableException;").append(ln);
        // 1.2引入代理接口類
        for (Class<?> interfaceClass : interfaces) {
            proxySrc.append("import ").append(interfaceClass.getName()).append(";").append(ln);
        }
        // 2類名、繼承及實現類,類開始
        proxySrc.append("public final class $GMProxy0 extends GMProxy implements ")
                // 實現的接口
                .append(getInterfacesStr(interfaces)).append(" {");

        // hashCode
        proxySrc.append("\nprivate static Method m0;").append(ln);
        // equals
        proxySrc.append("private static Method m1;").append(ln);
        // toString
        proxySrc.append("private static Method m2;").append(ln);
        // 獲取實現類的方法
        proxySrc.append(getImplementAndMethodsStr(getMethodsThatImplements(interfaces))).append(ln);

        // 構造方法
        proxySrc.append("public $GMProxy0(GMInvocationHandler h) { super(h); }").append(ln);

        // hashCode
        proxySrc.append("public final int hashCode() {\n" +
                "        try {\n" +
                "            return (Integer)super.h.invoke(this, m0, null);\n" +
                "        } catch (RuntimeException | Error var2) {\n" +
                "            throw var2;\n" +
                "        } catch (Throwable var3) {\n" +
                "            throw new UndeclaredThrowableException(var3);\n" +
                "        }\n" +
                "    }").append(ln);

        // equals
        proxySrc.append(" public final boolean equals(Object var1) {\n" +
                "        try {\n" +
                "            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});\n" +
                "        } catch (RuntimeException | Error var3) {\n" +
                "            throw var3;\n" +
                "        } catch (Throwable var4) {\n" +
                "            throw new UndeclaredThrowableException(var4);\n" +
                "        }\n" +
                "    }").append(ln);

        // toString
        proxySrc.append("public final String toString() {" +
                "try {\n" +
                "            return (String)super.h.invoke(this, m2, null);\n" +
                "        } catch (RuntimeException | Error var2) {\n" +
                "            throw var2;\n" +
                "        } catch (Throwable var3) {\n" +
                "            throw new UndeclaredThrowableException(var3);\n" +
                "        }" +
                "}").append(ln);


        // 代理接口的方法
        proxySrc.append(getMethodsImplementStr(getMethodsThatImplements(interfaces)));

        // 調用方法
        proxySrc.append("static {\n" +
                "        try {\n" +
                "            m0 = Class.forName(\"java.lang.Object\").getMethod(\"hashCode\");\n" +
                "            m1 = Class.forName(\"java.lang.Object\").getMethod(\"equals\", Class.forName(\"java.lang.Object\"));\n" +
                "            m2 = Class.forName(\"java.lang.Object\").getMethod(\"toString\");\n")
                .append(getStaticMethodValue(getMethodsThatImplements(interfaces)))
                .append("} catch (NoSuchMethodException var2) {\n")
                .append("            throw new NoSuchMethodError(var2.getMessage());\n")
                .append("        } catch (ClassNotFoundException var3) {\n")
                .append("            throw new NoClassDefFoundError(var3.getMessage());\n")
                .append("        }\n")
                .append("    }");


        // 類結束
        proxySrc.append("}");

        return proxySrc.toString();
    }

    /**
     * 獲取實現接口的字符串
     *
     * @param interfaces
     * @return
     */
    private static String getInterfacesStr(Class<?>[] interfaces) {
        String ln = ",";
        StringBuilder interfaceNames = new StringBuilder();
        for (Class<?> interfaceClass : interfaces) {
            interfaceNames.append(interfaceClass.getSimpleName()).append(ln);
        }
        String interfacesStr = interfaceNames.toString();
        return interfacesStr.substring(0, interfacesStr.length() - 1);
    }

    /**
     * 獲取接口的方法
     *
     * @return Map
     */
    private static Map<String, Method[]> getMethodsThatImplements(Class<?>[] interfaces) {
        Map<String, Method[]> implementAndMethods = new HashMap<>();

        for (Class<?> anInterface : interfaces) {
            implementAndMethods.put(anInterface.getName(), anInterface.getMethods());
        }
        return implementAndMethods;
    }

    /**
     * 獲取接口的方法的拼接字符串
     *
     * @param implementAndMethods
     * @return
     */
    private static String getImplementAndMethodsStr(Map<String, Method[]> implementAndMethods) {
        StringBuilder interfaceNames = new StringBuilder();

        for (String key : implementAndMethods.keySet()) {
            Method[] methods = implementAndMethods.get(key);
            for (Method method : methods) {
                interfaceNames.append("private static Method ").append(method.getName()).append(";").append("\r\n");
            }
        }

        return interfaceNames.toString();
    }

    /**
     * 代理方法的實現,字符串
     *
     * @param implementAndMethods
     * @return
     */
    private static String getMethodsImplementStr(Map<String, Method[]> implementAndMethods) {
        StringBuilder methodsImplement = new StringBuilder();
        for (String key : implementAndMethods.keySet()) {
            Method[] methods = implementAndMethods.get(key);
            for (Method method : methods) {
                Class<?> returnType = method.getReturnType();
                String returnTypeName = returnType.getName();
                String methodName = method.getName();
                if (returnTypeName.equals("void")) {
                    methodsImplement
                            .append("public final void ").append(methodName).append("() {\n")
                            .append("        try {\n")
                            .append("            super.h.invoke(this, ").append(methodName).append(", null);\n")
                            .append("        } catch (RuntimeException | Error var2) {\n")
                            .append("            throw var2;\n")
                            .append("        } catch (Throwable var3) {\n")
                            .append("            throw new UndeclaredThrowableException(var3);\n")
                            .append("        }\n")
                            .append("    }").append("\r\n");
                } else {
                    methodsImplement
                            .append("public final ").append(returnTypeName).append(" ").append(methodName).append("() {\n")
                            .append("        try {\n")
                            .append("            return (").append(returnTypeName)
                            .append(")super.h.invoke(this, ")
                            .append(methodName)
                            .append(", null);\n")
                            .append("        } catch (RuntimeException | Error var2) {\n")
                            .append("            throw var2;\n").append("        } catch (Throwable var3) {\n")
                            .append("            throw new UndeclaredThrowableException(var3);\n")
                            .append("        }\n")
                            .append("    }").append("\r\n");
                }
            }
        }
        return methodsImplement.toString();
    }

    /**
     * 獲取調用方法,字符串
     *
     * @param implementAndMethods
     * @return
     */
    private static String getStaticMethodValue(Map<String, Method[]> implementAndMethods) {
        StringBuilder staticMethodValue = new StringBuilder();
        for (String key : implementAndMethods.keySet()) {
            Method[] methods = implementAndMethods.get(key);
            for (Method method : methods) {
                staticMethodValue.append("            ")
                        .append(method.getName())
                        .append(" = Class.forName(\"").append(key)
                        .append("\").getMethod(\"").append(method.getName()).append("\");\n");
            }
        }
        return staticMethodValue.toString();
    }

}

8. 再寫一個媒婆類

實現 GMInvocationHandler

GMMatchmaker.java

package proxy.self;

import proxy.jdk.XiaoJuu;

import java.lang.reflect.Method;

/**
 * 媒婆
 *
 * @author 周廣明
 * @version v1 2020/2/16 9:57
 */
public class GMMatchmaker implements GMInvocationHandler {

    private XiaoJuu target;

    public Object getInstance(XiaoJuu target) throws Exception {
        this.target = target;

        Class<? extends XiaoJuu> targetClass = target.getClass();
        System.out.println("被代理者:" + targetClass);

        // 獲取並返回代理對象
        return GMProxy.newProxyInstance(new GMClassLoader(), targetClass.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String sex = "男".equals(this.target.getSex()) ? "媳婦" : "老公";

        System.out.println("----------------");
        method.invoke(this.target, args);
        System.out.println("----------------");

        System.out.println("\n媒婆:你的性別是" + this.target.getSex() + ",需要找" + sex);
        System.out.println("\n開始找" + sex + "...");
        System.out.println("\n找到小ZZ,覺得闊以,那就辦事");

        return null;
    }


}

9. 相親者 XiaoJuu

XiaoJuu.java

package proxy.jdk;

/**
 * 相親者
 *
 * @author 周廣明
 * @version v1 2020/2/15 14:50
 */
public class XiaoJuu implements Person {

    private String name = "小Juu";

    private String sex = "女";

    @Override
    public String getName(String aa, int bb) {
        return name;
    }

    @Override
    public String getSex() {
        return sex;
    }

    @Override
    public void findLove() {
        System.out.println("姓名:" + name + ",性別:" + sex);
        System.out.println("找對象要求:");
        System.out.println("高富帥");
        System.out.println("有車有房");
        System.out.println("身高180cm,體重70kg");
    }
}

10. 安排相親

TestWoo.java

package proxy.jdk;

import proxy.self.GMMatchmaker;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;

/**
 * @author 周廣明
 * @version v1 2020/2/15 14:58
 */
public class TestWoo {

    public static void main(String[] args) {
        // 要相親者
        XiaoJuu xiaoJuu = new XiaoJuu();

        // 媒婆出場
        GMMatchmaker meiPo = new GMMatchmaker();

        // 代理對象
        try {
            Person obj = (Person) meiPo.getInstance(xiaoJuu);
            System.out.println("代理人:" + obj.getClass() + "\n");
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

11. 相親結果

被代理者:class proxy.jdk.XiaoJuu
代理人:class proxy.self.$GMProxy0

----------------
姓名:小Juu,性別:女
找對象要求:
高富帥
有車有房
身高180cm,體重70kg
----------------

媒婆:你的性別是女,需要找老公

開始找老公...

找到小ZZ,覺得闊以,那就辦事

Process finished with exit code 0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章