通过字节重组,重新生成对象来代替原始对象,以达到代理的目的。

字节码重组的基本步骤如下:

1.获取被代理对象的引用,利用反射获取到它的所有接口。

2.JDK动态代理类Proxy重新生成一个新的类,此类要实现刚才获取到的所有接口。

3.动态生成新类的Java代码。

4.编译.java文件成.class文件。

5.加载编译好的.class文件。

创建Person接口:

public interface Person {
    void sing();
}

创建Customer类:

public class Customer implements Person{

    @Override
    public void sing() {
        System.out.println("唱的很好听");
    }
}

创建MyInvocationHandler接口:

import java.lang.reflect.Method;

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

自定义类加载器MyClassLoader:

import java.io.*;

public class MyClassLoader extends ClassLoader {

    private File classPathFile;

    public MyClassLoader() {
        //class文件路径
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    /**
     * 寻找需要加载的class文件并返回类对象
     *
     * @param name 类名称
     * @return 找到Class对象
     * @throws ClassNotFoundException
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = MyClassLoader.class.getPackage().getName() + "." + name;

        if (null != classPathFile) {
            File classFile = new File(classPathFile, name + ".class");
            if (classFile.exists()) {
                FileInputStream fis = null;
                ByteArrayOutputStream baos = null;

                try {
                    fis = new FileInputStream(classFile);
                    baos = new ByteArrayOutputStream();

                    byte[] buff = new byte[1024];
                    int len;

                    while ((len = fis.read(buff)) != -1){
                        baos.write(buff,0,len);
                    }

                    return defineClass(className,baos.toByteArray(),0,baos.size());

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (null != fis) {
                        try {
                            fis.close();

                            if (null != baos) {
                                baos.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

自定义Proxy类MyProxy:

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 MyProxy {

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

    public static Object newMyProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler handler) {

        try {

            String src = generateSrc(interfaces);
            //将Java文件输出到磁盘上
            String filePath = MyProxy.class.getResource("").getPath() + "$Proxy0.java";
            File file = new File(filePath);
            FileWriter fw = new FileWriter(file);
            fw.write(src);
            fw.flush();
            fw.close();

            //编译Java文件成class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(file);

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

            //加载类
            Class proxyClass = classLoader.findClass("$Proxy0");
            Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);
            file.delete();

            return constructor.newInstance(handler);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    private static String generateSrc(Class<?>[] interfaces) {

        StringBuffer sb = new StringBuffer();

        sb.append("package com.study.demo.proxy2;" + ln);
        sb.append("import com.study.demo.proxy2.Person;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("MyInvocationHandler handler;" + ln);
        sb.append("public $Proxy0(MyInvocationHandler handler) {" + ln);
        sb.append("this.handler = handler;");
        sb.append("}" + ln);


        for (Method m : interfaces[0].getMethods()) {
            //获得每个方法的形式参数
            Class<?>[] params = m.getParameterTypes();
            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValus = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();

            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                //将类写名称第一个字母小写order
                String paramName = toLowerFirstCase(clazz.getSimpleName());

                paramNames.append(type + " " + paramName);
                paramValus.append(paramName);
                //cn.xupt.design_pattern.structure.proxy.handwriting_dynamic_proxy.Order.class
                paramClasses.append(clazz.getName() + ".class");

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

            }

            //构造各个方法
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + " " + "(" +
                    paramNames.toString() + "){" + ln);
            sb.append("try{" + ln);
            sb.append("Method method = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName()
                    + "\", new Class[]{" + paramClasses.toString() + "});" + ln);
            sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode(
                    "this.handler.invoke(this, method, new Object[]{" + paramValus + "})", m.getReturnType()) + ";");
            sb.append("}catch(Error _ex){}");
            sb.append("catch(Throwable e){" + ln);
            sb.append("throw new UndeclaredThrowableException(e);" + ln);
            sb.append("}");
            sb.append(getReturnEmptyCode(m.getReturnType()));
            sb.append("}");
        }
        sb.append("}" + ln);
        return sb.toString();
    }

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

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

    private static String getReturnEmptyCode(Class<?> returnClass) {

        if (mapping.containsKey(returnClass)) {
            return "0";
        } else if (returnClass == void.class) {
            return "";
        } else {
            return "return null";
        }
    }

    private static String getCaseCode(String code, Class<?> returnClass) {

        if (mapping.containsKey(returnClass)) {
            return "((" + mapping.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

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

    private static String toLowerFirstCase(String src) {

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

创建歌手类Singer:

import java.lang.reflect.Method;

public class Singer implements MyInvocationHandler{

    private Object target;

    public Object getInstance(Object target) {
        this.target = target;
        Class<?> aClass = target.getClass();
        return MyProxy.newMyProxyInstance(new MyClassLoader(), aClass.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        Object invoke = method.invoke(this.target, args);
        after();
        return invoke;
    }

    private void before() {
        System.out.println("我是歌手");
    }

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

}

创建Client类

public class Test {

    public static void main(String[] args) {
        Person person = (Person) new Singer().getInstance(new Customer());
        person.sing();
    }
}