深度模拟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     @Override
20     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)运行结果

 

posted @ 2015-09-17 20:49  苏幕遮soft  阅读(236)  评论(0编辑  收藏  举报