深度模拟java动态代理实现机制系类之二
这次我们要实现的是对任意接口,任意的方法进行特定的代理
这里不一样的只有Proxy类,要实现对所有方法进行代理,那么重点就在于获得接口的所有方法
1 import java.io.File; 2 import java.io.FileWriter; 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 import java.net.URL; 6 import java.net.URLClassLoader; 7 8 import javax.tools.JavaCompiler; 9 import javax.tools.StandardJavaFileManager; 10 import javax.tools.ToolProvider; 11 import javax.tools.JavaCompiler.CompilationTask; 12 13 //该类实现了对任意接口,任意方法的特定代理 14 public class ProxyG2 { 15 //产生新的动态代理类 16 public static Object newProxyInstance(Class intf) throws Exception{ //将接口当成参数传入,这样就可以代理实现了任意接口的类,而不仅是实现了Moveable接口 17 String methodsString = ""; //获得所有方法字符串 18 String rt = "\r\n"; 19 20 Method[] methods = intf.getMethods(); 21 for(Method m : methods){ 22 methodsString += "@Override "+ rt+ 23 "public void "+m.getName()+" (){"+"" +rt+ 24 " long start = System.currentTimeMillis();"+rt+ 25 " System.out.println(\"start time is \"+start);"+rt+ 26 " t."+m.getName()+"();"+rt+ 27 " long end = System.currentTimeMillis();"+rt+ 28 " System.out.println(\"end time is \"+end);"+rt+ 29 " System.out.println(\"time is \"+(end - start));"+rt+ 30 "}"+rt; 31 } 32 33 34 //将一下字符串动态编译,生成代理类 35 //实现方式有以下击中:jdk6.0 complier API;CGLib; ASM 36 37 String src = 38 "public class TankTimeProxy implements " +intf.getName()+ "{"+rt+ //直接用intf,是调用toString方法,前会加入字符串 interface 39 " Moveable t;"+rt+ 40 41 " public TankTimeProxy("+intf.getName()+" t) {"+rt+ 42 " this.t = t;"+rt+ 43 " }"+rt+ 44 45 methodsString+ 46 "}"; 47 48 //进行编译 49 String fileName = "g:/src/TankTimeProxy.java";//放在指定的地方 50 File f = new File(fileName); 51 FileWriter fw = new FileWriter(f); 52 //System.out.println(fileName); 53 fw.write(src); //写入内容 54 55 fw.flush(); 56 fw.close(); 57 58 //进行编译 59 //首先获得编译器 60 //compiler 为java编译器 javac 61 //获得编译器对象 62 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 63 //System.out.println(compiler.getClass().getName());//取得类名 64 //参数含义 (编译诊断,locale,charset) 65 //管理动态生成d文件 66 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);//默认值 67 //根据参数获取多个java文件 返回java文件对象 68 Iterable units = fileManager.getJavaFileObjects(fileName); 69 70 //“编译任务”对象 71 JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units); 72 task.call();//调用 73 fileManager.close(); 74 //System.out.println("***************************************"); 75 76 //************以上过程获得了java文件源码,编译生成了java文件的class文件******* 77 //加载至内存,生成新对象 78 //Class.load(0 是加载path路径的class文件 79 //URLClassLoader是将硬盘中的class文件加载进入 80 81 //通过Url引入本地文件 82 URL[] urls = new URL[]{new URL("file:/"+"g:/src/")}; //访问本地文件 指定class文件存放的位置 83 //去指定路径寻找class文件 84 URLClassLoader urlClassLoader = new URLClassLoader(urls); 85 86 Class c = urlClassLoader.loadClass("TankTimeProxy"); 87 88 System.out.println(c); 89 90 //执行 91 //c.newInstance(); 是调用空的构造方法 92 93 //获得构造方法 94 //根据java虚拟机,每一个构造方法也相当于一个对象 95 Constructor constructor = c.getConstructor(intf); 96 97 //产生新对象 98 Object m = constructor.newInstance(new Tank()); //new Tank()为构造方法的参数 即被代理对象 99 100 //m.move(); 101 102 return m; 103 } 104 }