天天看點

手寫JDK動态代理

一,JDK動态代理

    在純手寫動态代理前,首先分析一套标準JDK動态代理的執行流程。

1,目标類頂層接口

public interface ProxyInterface {

    public void targetMethod();
}
           

2,目标類

public class JDKProxyTarget implements ProxyInterface{

    @Override
    public void targetMethod() {
        System.out.println("代理方法...");
    }
}
           

3,代理類

public class JDKProxy {

    private ProxyInterface proxyInterface;

    public JDKProxy(ProxyInterface proxyInterface) {
        this.proxyInterface = proxyInterface;
    }

    public Object instanceProxy() {
        System.out.println("代理方法開始...");
        ProxyInterface instance = (ProxyInterface) Proxy.newProxyInstance(
                proxyInterface.getClass().getClassLoader(),
                proxyInterface.getClass().getInterfaces(),
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                method.invoke(proxyInterface, args);
                System.out.println("代理方法結束...");
                return null;
            }
        });
        return instance;
    }

}
           

4,測試類

public class JDKProxyTest {
    public static void main(String[] args) throws Exception {
        JDKProxy proxy = new JDKProxy(new JDKProxyTarget());
        ProxyInterface proxyInterface = (ProxyInterface) proxy.instanceProxy();
        System.out.println(proxyInterface.getClass());
        proxyInterface.targetMethod();
    }
}
           
手寫JDK動态代理

5,代碼解析

    a,Proxy.newInstance()方法

        * 第一個參數為目标類的類加載器

        * 第二個參數為目标類的接口集合,JDK動态代理目标類必須實作一個接口,這是為了保證生成的代理類和目标類之前的強一緻性關系

        * 第三個參數為InvocationHandler接口的實作類,這裡直接通過匿名内部類實作,重寫了invoke方法

    b,InvocationHandler接口實作類

        * 實作該類必須重寫invoke()方法,動态代理實作在代理類中該接口的實作類調用該方法,并在該方法中反射執行該方法完成整個動态代理流程;

        * 第一個參數為生成的動态代理對象;

        * 第二個參數為動态代理在用戶端執行的方法;

        * 第三個參數為該方法的參數清單;

        * 通過反射來完成方法調用;

    c,通過a步驟後,JDK會虛拟生成一個$Proxy0類,該類也實作了目标類實作的接口,進而多态傳回該虛拟類對象,可以通過代碼輸出該類

    * 代碼

public class JDKProxyTest {
    public static void main(String[] args) throws Exception {
        JDKProxy proxy = new JDKProxy(new JDKProxyTarget());
        ProxyInterface proxyInterface = (ProxyInterface) proxy.instanceProxy();
        System.out.println(proxyInterface.getClass());
        proxyInterface.targetMethod();

        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{ProxyInterface.class});
        FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
        outputStream.write(bytes);
        outputStream.close();
    }
}
           

    * $Proxy0類 --- 生成為.class檔案,直接通過IDEA進行反編譯

手寫JDK動态代理
public final class $Proxy0 extends Proxy implements ProxyInterface {
    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})).booleanValue();
        } 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 targetMethod() 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)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.gupao.designpattern.proxy.jdk.ProxyInterface").getMethod("targetMethod", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
           

    d, 可以看到該虛拟類繼承Proxy類并實作了目标類頂層接口,并反射擷取了目标類中的所有方法的Method對象;

    e, 同時,虛拟類也同時重寫了目标類的所有方法,并通過下列方式進行調用

super.h.invoke(this, m3, (Object[])null);
           

        super : 指該代理類的超類,也就是Proxy;

        h : 點進源碼可以看到這樣一行聲明

protected InvocationHandler h;
           

 在虛拟類的構造器中,也擷取了InvocationHandler的引用,是以,這裡的h,指的也就是在匿名内部類定義的實作類對象;

        h.invoke():就是調用匿名内部類中重寫的invoke()方法,分别傳遞參數該對象(this),執行的方法(method),方法參數(null);

二,手寫動态代理步驟分析

    從上面标準的JDK動态流程可以看出,手寫動态代理,需要這樣幾個類

    1,SelfProxy類,定義newInstance()方法,進行代理對象建立

        * 在該方法中首先需要輸出代理類的.java檔案

        * 編譯該.java檔案生成.class檔案

        * 通過類加載器加載該.class檔案

        * 生成該.class檔案的事例對象作為代理對象傳回

    2,SelfInvocationHandler接口,定義invoke()方法,在代理類中進行目标方法調用

        * 在.java檔案中,定義構造器,傳遞該類引用

        * 通過SelfInvocationHandler實作類對象調用invoke()方法,實作代理方式的方法調用

    3,SelfClassloader,自定義類加載器,繼承JDK的ClassLoader類,實作自定義的加載方式

    4,SelfJDKProxy,實作SelfInvocationHandler接口,重寫invoke()方法,實作最終方法運作

三,手寫動态代理代碼實作

1,目标類頂層接口

public interface SelfProxyInterface {

    public void targetMethod();
}
           

2,目标類

public class SelfJDKProxyTarget implements SelfProxyInterface{

    @Override
    public void targetMethod() {
        System.out.println("代理方法...");
    }
}
           

3,SelfClassLoader類 -- 自定義類加載器,加載.class到JVM記憶體中

public class SelfClassLoader extends ClassLoader{

    private File classPathFile;

    public SelfClassLoader() {
        String classPath = SelfClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = SelfClassLoader.class.getPackage().getName() + "." + name;
        if (null != classPathFile) {
            File classFile = new File(classPathFile, name + ".class");
            if (classFile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] bytes = new byte[1024];
                    int len;
                    while((len = in.read(bytes)) != -1) {
                        out.write(bytes, 0, len);
                    }

                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (null != in) {
                            in.close();
                        }
                        if (null != out) {
                            out.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return null;
    }
}
           

4,SelfProxy類 -- 生成虛拟代理類,建立代理對象

public class SelfProxy {

    private static final String ENTER = "\r\n";

    public static Object newInstance(SelfClassLoader classLoader, Class<?>[] interfaces, SelfInvocationHandler h) {
        try {
            // 動态生成源代碼
            String srcClass = generateSrc(interfaces);
            // 輸出Java檔案
            String filePath = SelfProxy.class.getResource("").getPath()  + "$ProxyO.java";
            System.out.println(filePath);
            FileWriter fileWriter = new FileWriter(filePath);
            fileWriter.write(srcClass);
            fileWriter.flush();
            fileWriter.close();
            // 編譯Java檔案為class檔案
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = fileManager.getJavaFileObjects(filePath);
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
            task.call();
            fileManager.close();
            // 加載編譯生成的class檔案到JVM
            Class<?> proxyClass = classLoader.findClass("$ProxyO");
            Constructor<?> constructor = proxyClass.getConstructor(SelfInvocationHandler.class);
            // 删掉虛拟代理類
            File file = new File(filePath);
            file.delete();
            // 傳回位元組碼重組以後的代理對象
            return constructor.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("package com.gupao.designpattern.proxy.self;" + ENTER + ENTER);
        stringBuilder.append("import com.gupao.designpattern.proxy.jdk.ProxyInterface;" + ENTER);
        stringBuilder.append("import java.lang.reflect.Method;" + ENTER);
        stringBuilder.append("public class $ProxyO implements " + interfaces[0].getName() + "{" + ENTER);
            stringBuilder.append("SelfInvocationHandler h;" + ENTER);
            stringBuilder.append("public $ProxyO(SelfInvocationHandler h) {" + ENTER);
                stringBuilder.append("this.h = h;" + ENTER);
            stringBuilder.append("}" + ENTER);

        for (Method method : interfaces[0].getMethods()) {
            stringBuilder.append("public " + method.getReturnType().getName() + " " + method.getName() + "() {" + ENTER);
                stringBuilder.append("try {" + ENTER);
                    stringBuilder.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{});" + ENTER);
                    stringBuilder.append("this.h.invoke(this, m, null);" + ENTER);
                stringBuilder.append("} catch(Throwable able) {" + ENTER);
                stringBuilder.append("able.getMessage();" + ENTER);
                stringBuilder.append("}" + ENTER);
            stringBuilder.append("}" + ENTER + ENTER);
        }
        stringBuilder.append("}" + ENTER);
        return stringBuilder.toString();
    }

}
           

    該類代碼的具體步驟在注釋中已經寫明;

5,檢視生成的.java檔案

package com.gupao.designpattern.proxy.self;

import com.gupao.designpattern.proxy.jdk.ProxyInterface;

import java.lang.reflect.Method;

public class $ProxyO implements com.gupao.designpattern.proxy.self.SelfProxyInterface {
    SelfInvocationHandler h;

    public $ProxyO(SelfInvocationHandler h) {
        this.h = h;
    }

    public void targetMethod() {
        try {
            Method m = com.gupao.designpattern.proxy.self.SelfProxyInterface.class.getMethod("targetMethod", new Class[]{});
            this.h.invoke(this, m, null);
        } catch (Throwable able) {
            able.getMessage();
        }
    }

}
           

6,檢視生成的.class檔案

package com.gupao.designpattern.proxy.self;

import java.lang.reflect.Method;

public class $ProxyO implements SelfProxyInterface {
    SelfInvocationHandler h;

    public $ProxyO(SelfInvocationHandler var1) {
        this.h = var1;
    }

    public void targetMethod() {
        try {
            Method var1 = SelfProxyInterface.class.getMethod("targetMethod", new Class[0]);
            this.h.invoke(this, var1, (Object[])null);
        } catch (Throwable var2) {
            var2.getMessage();
        }

    }
}
           

7,SelfInvocationHandler接口,定義invoke()方法

public interface SelfInvocationHandler {

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

8,SelfJdkProxy,定義newInstance()方法建立代理對象,并實作InvocationHandler接口,重寫invoke()方法,通過反射實作方法最終運作

public class SelfJDKProxy implements SelfInvocationHandler{

    private SelfProxyInterface proxyInterface;

    public SelfJDKProxy(SelfProxyInterface proxyInterface) {
        this.proxyInterface = proxyInterface;
    }

    public Object instanceProxy() {
        System.out.println("代理方法開始...");
        SelfProxyInterface instance = (SelfProxyInterface) SelfProxy.newInstance(
                new SelfClassLoader(),
                proxyInterface.getClass().getInterfaces(), this);
        return instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        try {
            method.invoke(proxyInterface, args);
            System.out.println("代理方法結束...");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
           

9,用戶端執行

public class SelfTest {

    public static void main(String[] args) {
        SelfJDKProxy proxy = new SelfJDKProxy(new SelfJDKProxyTarget());
        SelfProxyInterface proxyInterface = (SelfProxyInterface) proxy.instanceProxy();
        System.out.println(proxyInterface);
        proxyInterface.targetMethod();
    }
}
           
手寫JDK動态代理

10,總結

    整個手寫動态代理以說明問題為目的,整個流程中所有環境建立都是按照最簡單方式在運作,旨在熟悉整個JDK動态代理的執行流程和底層實作;