深度模拟java动态代理实现机制系类之一

上一篇博客是最基本的动态代理原理的实现,因为其固定了接口,固定了代理方法,以及固定了代理的类型
接下来的博客系类将一步步渐入深度介绍java的动态代理的实现原理


****************************************************************************
首先补充一下“java代理”的相关知识,静态代理的实现包括两种方式,一是聚合,另一种是继承。
聚合是指通过接口,调用其实现类的具体方法:比如接口i,含有方法run(); 类A 实现了接口i,当然
也实现了方法run(); 类B于是就可以通过new一个接口 i 的对象,调用A的run()方法,并在run()方法前后实现其他操作,
这样就实现了对A的run()方法的代理;
继承当然更好理解,就是把run()方法重写,从而实现代理
但是,一旦代理的操作很多,需要写的类都非常的繁杂,就需要不断的写代理类,不断的更新代理操作,于是这就有了动
态代理。

*****************************************************************************

这次要对实现任意接口的类进行代理。

1、接口

public interface Moveable {
    void move();
}

  



2、被代理的对象

 1 public class Tank implements Moveable {
 2 
 3     @Override
 4     public void move() {
 5         
 6         System.out.println("Tank Moving...");
 7         try {
 8             Thread.sleep(new Random().nextInt(10000));
 9         } catch (InterruptedException e) {
10             e.printStackTrace();
11         }
12         
13     }
14     
15 }

 


3、用于产生代理对象

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

 




4、测试端

1 public class Client {
2     public static void main(String[] args) throws Exception {
3 
4         //这里任然以Moveable接口为例传入,因为在Proxy中为节省麻烦,还是固定生成了Moveable,后来会慢慢简化的,其实是可以传递任意的的接口的
5         Moveable m =(Moveable) Proxy.newProxyInstance(Moveable.class);
6         m.move();
7 
8     }
9 }

 



5、结果

(1)生成的java与class文件

(2)java文件的代码

(3)运行结果

posted @ 2015-09-17 17:59  苏幕遮soft  阅读(442)  评论(2编辑  收藏  举报