這里的內容就比較復雜了,要實現的是對任意的接口,對任意指定的方法,以及對任意指定的代理類型進行代理,就更真實的模擬出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动态代理实现机制系类之三的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。