一、概述
1.目标:把Proxy修改成可以代理任意接口及其任意方法
2.思路:
(1)代理任意接口:把接口类型作为参数传给Proxy的newProxyInstance(Class interfze)
(2)代理任意方法:用interfze.getMethods()取出所有方法,拼接实现方法的字符串
二、代码
1.Movable.java
2.Tank.java
3.Proxy.java
4.Client.java
1.Movable.java
1 package proxy; 2 3 public interface Movable { 4 public void move(); 5 public void stop(); 6 }
2.Tank.java
1 package proxy; 2 3 import java.util.Random; 4 5 public class Tank implements Movable { 6 7 @Override 8 public void move() { 9 System.out.println("Tank moving......."); 10 try { 11 Thread.sleep(new Random().nextInt(2000)); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 @Override 18 public void stop() { 19 System.out.println("Tank stopping......."); 20 21 } 22 23 }
3.Proxy.java
1 package proxy; 2 3 import java.io.File; 4 import java.io.FileWriter; 5 import java.lang.reflect.Constructor; 6 import java.lang.reflect.Method; 7 import java.net.URL; 8 import java.net.URLClassLoader; 9 10 import javax.tools.JavaCompiler; 11 import javax.tools.JavaCompiler.CompilationTask; 12 import javax.tools.StandardJavaFileManager; 13 import javax.tools.ToolProvider; 14 15 public class Proxy { 16 17 public static Object newProxyInstance(Class interfze) throws Exception { 18 19 String rt = "\n\r"; 20 21 //拼接"实现接口方法"的字符串 22 String methodStr = ""; 23 for(Method m: interfze.getMethods() ){ 24 25 //取出方法的修饰符和返回值类型 26 String [] parts = m.toString().replace("abstract ", "").split("\\."); 27 String [] parts2 = parts[0].split(" "); 28 29 methodStr += 30 "@Override" + rt + 31 parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt + 32 "System.out.println(\"Time Proxy start...........\");" + rt + 33 "long start = System.currentTimeMillis();" + rt + 34 "m." + m.getName() + "();" + rt + 35 "long end = System.currentTimeMillis();" + rt + 36 "System.out.println(\"花费时间:\"+(end - start));" + rt + 37 "System.out.println(\"Time Proxy end...........\");" + rt + 38 "}" ; 39 } 40 41 42 //动态代理文件的源码 43 String str = 44 "package proxy;" + rt + 45 46 "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+ 47 48 "private " + interfze.getName() + " m;" + rt + 49 50 "public TankTimeProxy(" + interfze.getName() + " m) {" + rt + 51 "this.m = m;" + rt + 52 "}" + rt + 53 54 methodStr + rt + 55 56 "}" ; 57 58 //把源码写到java文件里 59 File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java"); 60 FileWriter fw = new FileWriter(file); 61 fw.write(str); 62 fw.flush(); 63 fw.close(); 64 65 //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误 66 JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); 67 68 //文件管事器 69 StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null); 70 71 //编译单元 72 Iterable units = fileMgr.getJavaFileObjects(file); 73 74 //编译任务 75 CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units); 76 77 //编译 78 t.call(); 79 fileMgr.close(); 80 81 //把类load到内存里 82 URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")}; 83 URLClassLoader uc = new URLClassLoader(urls); 84 Class c = uc.loadClass("proxy.TankTimeProxy"); 85 86 //生成实例 87 //return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错 88 Constructor ctr = c.getConstructor(interfze); 89 return ctr.newInstance(new Tank()); 90 } 91 }
4.Client.java
1 package proxy; 2 3 import java.io.IOException; 4 5 import org.junit.Test; 6 7 public class Client { 8 9 @Test 10 public void testProxy() throws Exception{ 11 12 Movable m = (Movable)Proxy.newProxyInstance(Movable.class); 13 m.move(); 14 m.stop(); 15 16 } 17 }
三、运行结果