這里的內容就比較復雜了,要實現的是對任意的接口,對任意指定的方法,以及對任意指定的代理類型進行代理,就更真實的模擬出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)運行結果
?
轉載于:https://www.cnblogs.com/chentao-cus/p/4817584.html
總結
以上是生活随笔為你收集整理的深度模拟java动态代理实现机制系类之三的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。