实现自己的JDK动态代理- 2020-11-1 22:19- 设计模式: 设计模式,动态代理,JDK
jdk动态代理其实很简单,一般看过jdk动态代理生成的源码就明白了。
接口:HelloService
真实被代理类:HelloServiceImpl
自定义Proxy类(模拟原生Proxy类):MyProxy
自定义InvocationHandler(模拟InvocationHandler类):MyInvocationHandler
自定义ClassLoader(模拟ClassLoader):MyClassLoader
自定义动态代理 流程梳理
1.动态生成 代理类 .java文件
2.将java文件编译成class文件
3.将class文件加载进jvm
真实对象
/*** 接口类** @Author Bai* @Date 2020-10-26 14:25*/public interface HelloService {void say(String msg);}
实现自己的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;/*** 实现自己的Proxy类** @Author Bai* @Date 2020-11-08 12:14*/public class MyProxy {public static final String ln = "\r\n";public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h) {try {//1、动态生成源代码.java 文件String src = generateSrc(interfaces);System.out.println(src);// 2、Java 文件输出磁盘String filePath = MyProxy.class.getResource("").getPath();System.out.println(filePath);File f = new File(filePath + "$Proxy0.java");FileWriter fw = new FileWriter(f);fw.write(src);fw.flush();fw.close();// 3、把生成的.java 文件编译成.class 文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);Iterable iterable = manage.getJavaFileObjects(f);JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);task.call();manage.close();//4、编译生成的.class 文件加载到 JVM 中来Class proxyClass = classLoader.findClass("$Proxy0");Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);f.delete();//5、返回字节码重组以后的新的代理对象return c.newInstance(h);} catch (Exception e) {e.printStackTrace();}return null;}private static String generateSrc(Class<?>[] interfaces) {StringBuffer sb = new StringBuffer();sb.append("package com.xy.blog.test.poxy.my.jdkdynamic;" + ln);sb.append("import com.xy.blog.test.poxy.my.jdkdynamic.MyInvocationHandler;" + ln);sb.append("import com.xy.blog.test.poxy.my.jdkdynamic.MyProxy;" + ln);sb.append("import com.xy.blog.test.poxy.HelloService;" + ln);sb.append("import java.lang.reflect.*;" + ln);sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);sb.append("MyInvocationHandler h;" + ln);sb.append("public $Proxy0(MyInvocationHandler h) { " + ln);sb.append("this.h = h;");sb.append("}" + ln);for (Method m : interfaces[0].getMethods()) {Class<?>[] params = m.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(paramName);paramClasses.append(clazz.getName() + ".class");if (i > 0 && i < params.length - 1) {paramNames.append(",");paramClasses.append(",");paramValues.append(",");}}sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + ") {" + ln);sb.append("try{" + ln);sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses.toString() + "});" + ln);sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + "this.h.invoke(this,m,new Object[]{" + paramValues + "});" + ln);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 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);}private static String getReturnEmptyCode(Class<?> returnClass) {if (returnClass == void.class) {return "";} else {return "return null;";}}}
实现自己的JDK动态代理handler
import java.lang.reflect.Method;/*** 实现自己的JDK动态代理handler** @Author Bai* @Date 2020-11-08 12:14*/public interface MyInvocationHandler {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
实现自己的classLoader
import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;/*** 实现自己的classLoader** @Author Bai* @Date 2020-11-08 12:45*/public class MyClassLoader extends ClassLoader {private File classPathFile;public MyClassLoader() {String classPath = MyClassLoader.class.getResource("").getPath();this.classPathFile = new File(classPath);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String className = MyClassLoader.class.getPackage().getName() + "." + name;if (classPathFile != null) {File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".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);}return defineClass(className, out.toByteArray(), 0, out.size());} catch (Exception e) {e.printStackTrace();} finally {if (null != in) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (out != null) {try {out.close();} catch (IOException e) {e.printStackTrace();}}}}}return null;}}
实现HelloInvocationHandler
import com.xy.blog.test.poxy.HelloService;import sun.misc.ProxyGenerator;import java.io.FileOutputStream;import java.io.IOException;import java.lang.reflect.Method;/*** JDK动态代理handler** @Author Bai* @Date 2020-10-26 14:52*/public class HelloMyInvocationHandler implements MyInvocationHandler {/*** 真实对象:被代理的对象引用*/private Object target;public HelloMyInvocationHandler(Object target) {super();this.target = target;}/*** @param proxy 代理类* @param method 目标方法* @param args 入参* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("MyInvocationHandler#invoke start");//两者执行有何区别?target or proxy//proxy 会造成死循环,猜测可能是因为invoke内部实现 需要生成proxy的实例,去调用proxy实例的invoke,就会造成循环调用// Object invoke = method.invoke(proxy, args);Object invoke = method.invoke(target, args);System.out.println("MyInvocationHandler#invoke end");return invoke;}/*** 获取jdk生成的代理对象** @return*/public Object getProxy() {//下面的写法会报错 因为第二个入参需要的是接口对象,而target是具体实现类的引用 并发接口// return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{target.getClass()}, this);//第一个入参 使用哪个loader将proxy对象加载到内存中,一般是跟被代理对象同个loader就可以//第二个入参 proxy要代理的是哪些接口Class<?> aClass = target.getClass();return MyProxy.newProxyInstance(new MyClassLoader(), aClass.getInterfaces(), this);}private void saveProxyClass0() {//通过反编译工具可以查看源代码byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{HelloService.class});try {FileOutputStream os = new FileOutputStream("E://$Proxy0.class");os.write(bytes);os.close();} catch (IOException e) {e.printStackTrace();}}}
测试
/*** 实现自己的jdk动态代理*/@Testpublic void jdkMyProxyTest() throws Throwable {//真实对象HelloService helloService = new HelloServiceImpl();//代理handlerHelloMyInvocationHandler handler = new HelloMyInvocationHandler(helloService);// 代理对象HelloService helloProxyService = (HelloService) handler.getProxy();//使用代理对象执行System.out.println("--- helloProxyService.result ---");helloProxyService.say("helloProxyService.自己的jdk动态代理");helloProxyService.eat("累了 开吃");}
**
