Java ------ 實現自己的動態代理

代理的接口

public interface Person {

    int take();
}

需要被增強的類

import com.example.pattern.proxy.Person;

public class Boy implements Person {
    @Override
    public int take() {
    	System.out.println("-- boy --");
        return 1;
    }
}

自定義 InvocationHandler

用於提供被增強的方法 invoke()
SelfInvocationHandler.java

import java.lang.reflect.Method;

public interface SelfInvocationHandler {

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

自定義ClassLoader

重寫findClass
SelfClassLoader.java

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

public class SelfClassLoader extends ClassLoader {

    URL classPathFile;

    public SelfClassLoader() {
        this.classPathFile = SelfClassLoader.class.getResource("");
    }

    @Override
    public Class findClass(String name) throws ClassNotFoundException {
        // 獲取文件所在路徑
        String className = SelfClassLoader.class.getPackage().getName() + "." + name;

        if (classPathFile != null) {
            // 獲取生成的 .class 文件
            File classFile = new File(classPathFile.getPath(), "$Proxy0.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);
                    }
                    // 把字節碼轉化爲Class
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return super.findClass(name);
    }
}

自定義增強類

import java.lang.reflect.Method;

public class SelfEnhancement implements SelfInvocationHandler {

    private Object target;

    public Object getInstance(Object person) throws Exception {
        this.target = person;
        Class<?> clazz = target.getClass();
        return SelfProxy.newProxyInstance(new SelfClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target, args);
        after();
        return obj;
    }

    private void before() {
        System.out.println("before");
    }

    private void after() {
        System.out.println("after");
    }
}

自定義處理Proxy

import javax.tools.JavaCompiler;
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;

public class SelfProxy {

    public static final String ln = "\r\n";

    public static Object newProxyInstance(SelfClassLoader loader, Class<?>[] interfaces, SelfInvocationHandler h) {
        try {
            // 1. 動態代理生成源碼
            String src = generateSrc(interfaces);

            // 2. Java文件輸出到磁盤
            String filePath = SelfProxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            
			// 編譯Java文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);

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

			// 把class加載到內存
            Class proxyClass = loader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(SelfInvocationHandler.class);

            return c.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new Object();
    }

    public static String generateSrc(Class<?>[] interfaces) {
        // 用代碼寫代碼
        StringBuffer sb = new StringBuffer();
        sb.append("package com.example.pattern.proxy.dynamicproxy.selfproxy;" + ln);
        sb.append("import com.example.pattern.proxy.Person;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + " {" + ln);
        sb.append("SelfInvocationHandler h;" + ln);
        sb.append("public $Proxy0(SelfInvocationHandler h) {" + ln);
        sb.append("this.h = h;" + ln);
        sb.append("}");

        for (Method method : interfaces[0].getMethods()) {
            Class<?>[] params = method.getParameterTypes();

            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValues = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();

            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                String paramName = toLowerFirstCase(clazz.getSimpleName());
                paramNames.append(type + " " + paramName);
                paramValues.append(paramNames);
                paramClasses.append(clazz.getName() + ".class");

                if (i > 0 && i < params.length - 1) {
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }


            sb.append("public " + method.getReturnType().getName() + " " + method.getName() + "(" + paramNames.toString() + ") {" + ln);
            sb.append("try {" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{" + paramClasses.toString() + "});" + ln);
            sb.append(
                    (hasReturn(method.getReturnType()) ? "return " : "")
                            + getCaseCode("this.h.invoke(this, m, new Object[]{" + paramValues.toString() + "})",
                            method.getReturnType()) + ";" + ln);
            sb.append("} catch (Throwable e) {" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}" + ln);
            sb.append(getReturnEmptyCode(method.getReturnType()));
        }
        sb.append("}" + ln);
        sb.append("}");

        return sb.toString();
    }

    private static Map<Class, Class> mappings = new HashMap<>();

    static {
        mappings.put(int.class, Integer.class);
    }

    private static String getReturnEmptyCode(Class returnClass) {
        if (mappings.containsKey(returnClass)) {
            return "return 0;";
        } else if (returnClass == void.class) {
            return "";
        } else {
            return "return null;";
        }
    }

    private static String getCaseCode(String code, Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            return "((" + mappings.get(returnClass).getName() + ")" + code + ")";
        }
        return code;
    }

    private static boolean hasReturn(Class<?> clazz) {
        return clazz != void.class;
    }

    private static String toLowerFirstCase(String src) {
        char[] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }
}

測試代碼

public class SelfProxyTest {

    public static void main(String[] args) throws Exception {
        Person instance = (Person) new SelfEnhancement().getInstance(new Boy());
        instance.take();
    }
}

生成的代理類文件

package com.example.pattern.proxy.dynamicproxy.selfproxy;

import com.example.pattern.proxy.Person;

import java.lang.reflect.*;

public class $Proxy0 implements com.example.pattern.proxy.Person {
    SelfInvocationHandler h;

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

    public int take() {
        try {
            Method m = com.example.pattern.proxy.Person.class.getMethod("take", new Class[]{});
            return ((java.lang.Integer) this.h.invoke(this, m, new Object[]{}));
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return 0;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章