Spring学习——模拟jdk底层动态代理

Spring学习——模拟jdk底层动态代理

这里使用最简单的方法实现动态代理,即重新生成一个.java文件使用类加载器加载到内存,这与jdk底层的动态代理有所不同。

生成动态代理类的内容

通过字符串拼接出动态代理类的内容(强迫症必须要的对齐格式格式)

private static String generateProxyContentStr(Class clazz) {
        Method[] methods = clazz.getDeclaredMethods();

        String content = "package proxy;" + LINE + LINE;
        content +=
                "import com.hrious.javabasic.proxy.CustomInvocationHandler;" + LINE + LINE
                + "import java.lang.reflect.Method;" + LINE + LINE
                + "import " + clazz.getName() + ";" + LINE + LINE
                + "public class $Proxy implements UserDao {"
                + LINE + LINE
                + TAB + "private CustomInvocationHandler handler;"
                + LINE + LINE
                + TAB + "public $Proxy(CustomInvocationHandler handler) {"
                + LINE
                + TAB + TAB + "this.handler = handler;" + LINE
                + TAB + "}"
                + LINE + LINE;

        String methodStr = "";
        // 遍历每个方法
        for (Method method : methods) {
            methodStr +=
                    TAB + PUB + SPACE + method.getReturnType() + SPACE
                    + method.getName() + "(";

            Class<?>[] types = method.getParameterTypes();
            String paramStr = "";
            String declareType = "";
            if (types.length != 0) {
                declareType += ", ";
                for (int i = 0; i < types.length; i++) {
                    paramStr += types[i].getName() + SPACE + "i" + i + "," + SPACE;
                    declareType += types[i].getName() + ".class" + "," + SPACE;
                }
                paramStr = paramStr.substring(0, paramStr.length() - 2);
                declareType = declareType.substring(0, declareType.length() - 2);
            }
            methodStr += paramStr + ") {" + LINE
                    + TAB + TAB + "try {" + LINE
                    + TAB + TAB + TAB + "Class clazz = " + clazz.getSimpleName() + ".class;" + LINE
                    + TAB + TAB + TAB + "Method method = " + "clazz.getDeclaredMethod(\"" + method.getName() + "\"" + declareType + ");" + LINE;
            String objArrStr = "";
            if (types.length != 0) {
                objArrStr += "Object[] args = {";
                for (int i = 0; i < types.length; i++) {
                    objArrStr += SPACE + "i" + i + ",";
                }
                objArrStr = objArrStr.substring(0 ,objArrStr.length() - 1);
                objArrStr += " ";
                methodStr +=
                        TAB + TAB + TAB + objArrStr + "};" + LINE
                        + TAB + TAB + TAB + "return (" + method.getReturnType() + ") handler.invoke(method, args);" + LINE;
            } else {
                methodStr += TAB + TAB + TAB + "handler.invoke(method, null);" + LINE;
            }
            methodStr +=
                    TAB + TAB + "}" + LINE
                    + TAB + TAB + "catch (Throwable t) {" + LINE
                    + TAB + TAB + TAB + "throw new RuntimeException(t);" + LINE
                    + TAB + TAB + "}" + LINE + TAB + "}" + LINE + LINE;
        }

        content += methodStr + "}";
        return content;
    }

创建动态代理类(.java)

即把生成的动态代理类的内容通过IO操作的方式,写入到与之对应的.java文件中

private static String createProxyFile(String proxyContent) throws IOException {
        File dir = new File("D:\\proxy");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File("D:\\proxy\\$Proxy.java");
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file));) {
            bw.write(proxyContent);
            bw.flush();
            return "D:\\proxy\\$Proxy.java";
        } catch (IOException e) {
            throw e;
        }
    }

编译生成的.java文件

private static void complieProxyFile(String filePath) {
        File file = new File(filePath);
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMgr.getJavaFileObjects(file);

        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
        try {
            fileMgr.close();
        } catch (IOException e) {
        }
    }

通过类加载器加载.class文件

private static Class loadProxy2Mem() throws MalformedURLException, ClassNotFoundException {
        URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:d://")});
        return classLoader.loadClass("proxy.$Proxy");
    }

模拟jdk底层的newInstances方法

public static Object newInstances(Class inter, CustomInvocationHandler handler) {

        try {
            String proxyContent = generateProxyContentStr(inter);
            String filePath = createProxyFile(proxyContent);
            complieProxyFile(filePath);
            Class clazz = loadProxy2Mem();
            Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
            return constructor.newInstance(handler);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return  null;
    }

自定义的CustomProxy类

package com.hrious;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * 模拟jdk动态代理
 */
public class CustomProxy {
    private static final String LINE = "\r\n";
    private static final String TAB = "\t";
    private static final String PUB = "public";
    private static final String SPACE = " ";

    public static Object newInstances(Class inter, CustomInvocationHandler handler) {

        try {
            String proxyContent = generateProxyContentStr(inter);
            String filePath = createProxyFile(proxyContent);
            complieProxyFile(filePath);
            Class clazz = loadProxy2Mem();
            Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
            return constructor.newInstance(handler);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return  null;
    }

    /**
     * 将.class文件加载到内存
     * @return
     * @throws Exception
     */
    private static Class loadProxy2Mem() throws MalformedURLException, ClassNotFoundException {
        URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:d://")});
        return classLoader.loadClass("proxy.$Proxy");
    }

    /**
     * 编译生成的.java文件为.class文件
     */
    private static void complieProxyFile(String filePath) {
        File file = new File(filePath);
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMgr.getJavaFileObjects(file);

        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
        try {
            fileMgr.close();
        } catch (IOException e) {
        }
    }

    /**
     * 生成代理类的.java文件
     * @param proxyContent
     * @throws IOException
     */
    private static String createProxyFile(String proxyContent) throws IOException {
        File dir = new File("D:\\proxy");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File("D:\\proxy\\$Proxy.java");
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(file));) {
            bw.write(proxyContent);
            bw.flush();
            return "D:\\proxy\\$Proxy.java";
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 生成代理内容字符串
     * @param clazz
     * @return
     */
    private static String generateProxyContentStr(Class clazz) {
        Method[] methods = clazz.getDeclaredMethods();

        String content = "package proxy;" + LINE + LINE;
        content +=
                "import com.hrious.javabasic.proxy.CustomInvocationHandler;" + LINE + LINE
                + "import java.lang.reflect.Method;" + LINE + LINE
                + "import " + clazz.getName() + ";" + LINE + LINE
                + "public class $Proxy implements UserDao {"
                + LINE + LINE
                + TAB + "private CustomInvocationHandler handler;"
                + LINE + LINE
                + TAB + "public $Proxy(CustomInvocationHandler handler) {"
                + LINE
                + TAB + TAB + "this.handler = handler;" + LINE
                + TAB + "}"
                + LINE + LINE;

        String methodStr = "";
        // 遍历每个方法
        for (Method method : methods) {
            methodStr +=
                    TAB + PUB + SPACE + method.getReturnType() + SPACE
                    + method.getName() + "(";

            Class<?>[] types = method.getParameterTypes();
            String paramStr = "";
            String declareType = "";
            if (types.length != 0) {
                declareType += ", ";
                for (int i = 0; i < types.length; i++) {
                    paramStr += types[i].getName() + SPACE + "i" + i + "," + SPACE;
                    declareType += types[i].getName() + ".class" + "," + SPACE;
                }
                paramStr = paramStr.substring(0, paramStr.length() - 2);
                declareType = declareType.substring(0, declareType.length() - 2);
            }
            methodStr += paramStr + ") {" + LINE
                    + TAB + TAB + "try {" + LINE
                    + TAB + TAB + TAB + "Class clazz = " + clazz.getSimpleName() + ".class;" + LINE
                    + TAB + TAB + TAB + "Method method = " + "clazz.getDeclaredMethod(\"" + method.getName() + "\"" + declareType + ");" + LINE;
            String objArrStr = "";
            if (types.length != 0) {
                objArrStr += "Object[] args = {";
                for (int i = 0; i < types.length; i++) {
                    objArrStr += SPACE + "i" + i + ",";
                }
                objArrStr = objArrStr.substring(0 ,objArrStr.length() - 1);
                objArrStr += " ";
                methodStr +=
                        TAB + TAB + TAB + objArrStr + "};" + LINE
                        + TAB + TAB + TAB + "return (" + method.getReturnType() + ") handler.invoke(method, args);" + LINE;
            } else {
                methodStr += TAB + TAB + TAB + "handler.invoke(method, null);" + LINE;
            }
            methodStr +=
                    TAB + TAB + "}" + LINE
                    + TAB + TAB + "catch (Throwable t) {" + LINE
                    + TAB + TAB + TAB + "throw new RuntimeException(t);" + LINE
                    + TAB + TAB + "}" + LINE + TAB + "}" + LINE + LINE;
        }

        content += methodStr + "}";
        return content;
    }

    public static void main(String[] args) {
        UserDao userDao = (UserDao) newInstances(UserDao.class, new MyCustomInvocationHandler(new UserDaoImpl()));
        userDao.query();
//        userDao.insert(1, "张三");
    }
}

模拟InvocationHandler

package com.hrious;

import java.lang.reflect.Method;

/**
 * 自定义InvocationHandler接口,模拟jdk动态代理
 */
public interface CustomInvocationHandler {
    Object invoke(Method method, Object[] args) throws Throwable;
}

演示例子

UserDao接口

public interface UserDao {
    void query();
    int insert(int id, String name);
}

UserDao实现类

package com.hrious;

public class UserDaoImpl implements UserDao {
    @Override
    public void query() {
        System.out.println("UserDaoImpl query()");
    }

    @Override
    public int insert(int id, String name) {
        System.out.println("id:" + id + ", name:" + name);
        return 1;
    }
}

InvocationHandler增强逻辑

package com.hrious;

import java.lang.reflect.Method;

public class MyCustomInvocationHandler implements CustomInvocationHandler {
    private UserDao userDao;

    public MyCustomInvocationHandler(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public Object invoke(Method method, Object[] args) throws Throwable {
        System.out.println("my dynamic proxy");
        return method.invoke(userDao, args);
    }
}

测试方法

public static void main(String[] args) {
        UserDao userDao = (UserDao) newInstances(UserDao.class, new MyCustomInvocationHandler(new UserDaoImpl()));
        userDao.query();
//        userDao.insert(1, "张三");
    }

生成的代理类

package proxy;

import com.hrious.javabasic.proxy.CustomInvocationHandler;

import java.lang.reflect.Method;

import com.hrious.javabasic.proxy.UserDao;

public class $Proxy implements UserDao {

	private CustomInvocationHandler handler;

	public $Proxy(CustomInvocationHandler handler) {
		this.handler = handler;
	}

	public int insert(int i0, java.lang.String i1) {
		try {
			Class clazz = UserDao.class;
			Method method = clazz.getDeclaredMethod("insert", int.class, java.lang.String.class);
			Object[] args = { i0, i1 };
			return (int) handler.invoke(method, args);
		}
		catch (Throwable t) {
			throw new RuntimeException(t);
		}
	}

	public void query() {
		try {
			Class clazz = UserDao.class;
			Method method = clazz.getDeclaredMethod("query");
			handler.invoke(method, null);
		}
		catch (Throwable t) {
			throw new RuntimeException(t);
		}
	}

}

你可能感兴趣的:(Java)