通过字节重组,重新生成对象来代替原始对象,以达到代理的目的。
字节码重组的基本步骤如下:
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();
    }
}









