一、概述

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 .URL;
8 import .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 }


 

三、运行结果

Java-马士兵设计模式学习笔记-代理模式--动态代理 修改成可以代理任意接口_动态代理


You can do anything you set your mind to, man!