你的位置:首页 > ASP.net教程

[ASP.net教程]深度模拟java动态代理实现机制系类之三


这里的内容就比较复杂了,要实现的是对任意的接口,对任意指定的方法,以及对任意指定的代理类型进行代理,就更真实的模拟出java虚拟机的动态代理机制

罗列一下这里涉及的类、接口之间的关系,方便大家学习。
1、InvocationHandler接口,用来处理指定的方法,即对特定方法的代理,处理的具体实现交由子类实现
2、TimeHandler类,实现了InvocationHandler接口的子类,具体的代理实现是进行时间代理
3、Proxy类,用于产生代理类的类
4、Moveable接口,举例过程中各类要实现的统一接口
5、Tank类,实现了Moveable接口,即被代理的类
6、Cilent,操作客户端

先把整个的思路理一下:
首先在Client端,new一个被代理的对象Tank,Tank对象作为构造参数传入代理处理类TimeHandler,new出一个TimeHandler对象,
Tank的接口Moveable和TimeHandler对象作为参数传入Proxy,Proxy调用newProxyInstance方法,该方法中对接口的所有的方法,利用TimeHandler对象进行代理,(可以简单理解为将接口方法与TimeHandler代理方法结合),生成新的代理对象的java文件、class文件、然后加载进入内存,利用反射获得一个代理对象,返回该代理对象,在Client端调用则调用了代理对象方法;


1、InvocationHandler接口

1 package com.csu.proxy;2 3 import java.lang.reflect.Method;4 //对任意方法自定义处理5 //方法调用的处理器6 public interface InvocationHandler {  //定义一个接口,用来处理方法,处理的具体实现交由子类实现7 8   public void invoke(Object o, Method m); //对某个指定方法的处理9 }

 



2、TimeHandler类

 1 package com.csu.proxy; 2  3 import java.lang.reflect.Method; 4 public class TimeHandler implements InvocationHandler { 5  private Object target;//被代理的对象 6  7   public Object getT() { 8     return target; 9   }10 11   public void setT(Object t) {12     this.target = t;13   }14 15   public TimeHandler(Object target) {16     this.target = target;17   }18 19   @Override20   public void invoke(Object o,Method m){ //必须指定具体对象对具体的方法的调用21     long start = System.currentTimeMillis();22     System.out.println("start time is " + start);23     System.out.println(o.getClass().getName());24     //m 调用方法25     try {26       m.invoke(target); 27     } catch (Exception e) {e.printStackTrace();}28 29 30     long end = System.currentTimeMillis();31     System.out.println("end time is "+end);32     System.out.println("time is "+(end - start));33   }34 }

 


3、Moveable接口

1 package com.csu.proxy;2 3 public interface Moveable {4   void move();5 }

 



4、Tank类

 1 package com.csu.proxy; 2  3 import java.util.Random; 4  5  6 public class Tank implements Moveable { 7  8   @Override 9   public void move() {10     11     System.out.println("Tank Moving...");12     try {13       Thread.sleep(new Random().nextInt(10000));14     } catch (InterruptedException e) {15       e.printStackTrace();16     }17     18   }  19   20 }

 



5、Proxy类

 1 package com.csu.proxy; 2  3 import javax.tools.JavaCompiler; 4 import javax.tools.StandardJavaFileManager; 5 import javax.tools.ToolProvider; 6 import java.io.File; 7 import java.io.FileWriter; 8 import java.lang.reflect.Constructor; 9 import java.lang.reflect.Method; 10 import java.net.URL; 11 import java.net.URLClassLoader; 12  13 /** 14 方便大家阅读,关注主要的逻辑思路,将在前面博客的已经写过的注释代码清除,因为这是一系列,有很多代码引用 15 有想要看的,去上几篇文章看吧 16 **/ 17  18 //该类要实现对任意接口,任意方法,以及任意的代理 的实现 19 public class ProxyG3 { 20   public static Object newProxyInstance(Class intf, InvocationHandler h) throws Exception{ 21   //invocationHandler当成参数,指定代理的类型,即指定对方法要进行什么处理 22  23     //*****************1、获得java文件********************************** 24   String methodsString = "";  25     String rt = "\r\n"; 26  27     Method[] methods = intf.getMethods(); 28     for(Method m : methods) { 29       methodsString += "@Override" + rt + 30           "public void " + m.getName() + "() {" + rt + 31           "  try {" + rt + 32           "  Method md = " + intf.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + 33           "  h.invoke(this, md);" + rt + 34           "  }catch(Exception e) {e.printStackTrace();}" + rt + 35  36           "}"; 37     } 38  39     String src = 40             "package com.csu.proxy;" + rt + 41             "import java.lang.reflect.Method;" + rt + 42             "public class TankTimeProxy implements " + intf.getName() + "{" + rt + 43             "  public TankTimeProxy(InvocationHandler h) {" + rt + 44             "    this.h = h;" + rt + 45             "  }" + rt + 46  47  48             "  com.csu.proxy.InvocationHandler h;" + rt + 49  50             methodsString + 51             "}"; 52     String fileName = "g:/src/com/csu/proxy/TankTimeProxy.java";//放在指定的地方 53     File f = new File(fileName); 54     FileWriter fw = new FileWriter(f); 55     fw.write(src); 56     fw.flush(); 57     fw.close(); 58   /** 59   这里重点说一下:用于存放代理对象TankTimeProxy的java和class文件的包名要工程中的其他java文件的包名一致,查看代码你会发现 60   工程的java文件和生成的代理对象的java文件的包名都是 com.csu.proxy; 61   **/ 62  63     //****************2、获得class文件**************************************** 64  65    //获得编译器对象 66     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 67      68     //管理动态生成的文件 69     StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null); 70     Iterable units = fileManager.getJavaFileObjects(fileName); 71  72     //“编译任务”对象 73     JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units); 74     task.call(); 75     fileManager.close(); 76  77     //*****************3、加载至内存****************************************** 78  79     //通过Url引入本地文件 80     URL[] urls = new URL[]{new URL("file:/"+"g:/src/")}; //访问本地文件  指定class文件存放的位置 81     URLClassLoader urlClassLoader = new URLClassLoader(urls); 82     Class c = urlClassLoader.loadClass("com.csu.proxy.TankTimeProxy"); 83  84     //******************4、执行class文件,返回代理对象*************************************** 85  86     //获得构造方法 87     Constructor constructor = c.getConstructor(InvocationHandler.class); //getConstructor的参数为Class类型,是原构造方法的参数的Class类型 88  89     //产生新对象 90     Object m = constructor.newInstance(h); 91  92     return m; 93   } 94 } 95  96 6、Cilent客户端 97  98 package com.csu.proxy; 99 100 public class Client {101   public static void main(String[] args) throws Exception {102 103     Tank t = new Tank();104     InvocationHandler h = new TimeHandler(t);105 106     Moveable m =(Moveable) ProxyG3.newProxyInstance(Moveable.class, h);107 108     m.move();109 110 111   }112 }

 

 

7、执行结果

(1)生成的java和class文件

(2)查看生成的java文件代码

(3)运行结果