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

一、概述

1.目标:动态代理的代理逻辑可以任意修改

2.思路:

(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler) 

(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑

3.知识点:

(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");

(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");

 

二、代码

1.InvocationHandler.java

2.TimeHandler.java

3.Movable.java

4.Tank.java

5.Proxy.java

6.Client.java

 

1.InvocationHandler.java

1 package proxy;

2 

3 import java.lang.reflect.Method;

4 

5 public interface InvocationHandler {

6     public void invoke(Object o, Method m);

7 }

 

2.TimeHandler.java

 1 package proxy;

 2 

 3 import java.lang.reflect.InvocationTargetException;

 4 import java.lang.reflect.Method;

 5 

 6 public class TimeHandler implements InvocationHandler {

 7 

 8     //保留被代理的对象

 9     private Object target;

10     

11     public TimeHandler(Object target) {

12         this.target = target;

13     }

14 

15     @Override

16     public void invoke(Object o, Method m) {

17         System.out.println("Time Proxy start...........");

18         long start = System.currentTimeMillis();

19         try {

20             //除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去

21             m.invoke(target);    

22         } catch (Exception e) {

23             e.printStackTrace();

24         } 

25         long end = System.currentTimeMillis();

26         System.out.println("花费时间:"+(end - start));

27         System.out.println("Time Proxy end...........");

28 

29     }

30 

31 }

 

3.Movable.java

1 package proxy;

2 

3 public interface Movable {

4     public void move();

5     public void stop();

6 }

 

4.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 }

 

5.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,InvocationHandler handler) 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             "try{"+ rt +

33                 "java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""+m.getName()+"\");" + rt +

34                 //传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)

35                 "handler.invoke(this, md);" + rt +

36             "}catch(Exception e){"+ rt +

37             "    e.printStackTrace();" + rt +

38             "}" + rt +

39             

40                 

41             "}"+ rt ;

42         }

43         

44         

45         //动态代理文件的源码

46         String str = 

47         "package proxy;" + rt +

48 

49         "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+

50 

51             

52             //聚合Handler

53             "private InvocationHandler handler;" + rt +

54             

55             "public TankTimeProxy(InvocationHandler handler) {" + rt +

56                 "this.handler = handler;" + rt +

57             "}" + rt +

58 

59             methodStr + rt +

60 

61         "}" ;

62         

63         //把源码写到java文件里

64         File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java");

65         FileWriter fw = new FileWriter(file);

66         fw.write(str);

67         fw.flush();

68         fw.close();

69         

70         //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误

71         JavaCompiler jc = ToolProvider.getSystemJavaCompiler();

72         

73         //文件管事器

74         StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null);

75         

76         //编译单元

77         Iterable units = fileMgr.getJavaFileObjects(file);

78         

79         //编译任务

80         CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units);

81         

82         //编译

83         t.call();    

84         fileMgr.close();

85         

86         //把类load到内存里

87         URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};

88         URLClassLoader uc = new URLClassLoader(urls);

89         Class c = uc.loadClass("proxy.TankTimeProxy");

90         

91         //生成实例

92         //return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错

93         //Constructor ctr = c.getConstructor(interfze);

94         Constructor ctr = c.getConstructor(InvocationHandler.class);

95         return ctr.newInstance(handler);

96     }

97 }

 

6.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, new TimeHandler(new Tank()));

13         m.move();

14         m.stop();

15         

16     }

17 }

 

三、运行结果

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

 

你可能感兴趣的:(java)