代理Proxy:Core Java 6.5

利用代理可以在運行時創建一個實現了一組接口的新類。

這種功能只有在編譯時無法確定需要實現哪個接口時才使用。對於應用程序設計人員來說,遇到這種情況的機會很少。這是一種高級技術,對於系統程序設計人員來說,代理帶來的靈活性十分重要。

代理如何工作的

代理類可以在運行時創建全新的類。在運行時直接生成類,即Class類的一個實例。而非生成一個類的源碼,然後經過編譯後再生成類的字節碼文件,再經過JVM加載、生成類。因此運行時生成類性能很快。

代理類能夠實現指定的接口的所有需要的方法,並且也實現了Object類的toString、equals方法。

代理類並非是通過自己全新的定義來實現這些接口方法的,而是通過一個調用處理器即InvocationHandler接口的一個實例對象來實現的。

InvocationHandler接口中只有一個方法:

/*
@param  poxy 代理類
@param  method  當代理類工作時,調用被代理對象的那個方法;即代理類實現的接口方法。
@param  args   被代理的方法的參數
*/
Object  invoke(Object  proxy, Method method, Object[]  args)

代理類的代理作用即代理要做的工作就要寫在這個invoke方法中,再method.invoke(args);方法前後做一些必要的工作。

無論何時調用代理對象的方法,invoke方法都會被調用,invoke方法中必須給出處理調用的代碼。

創建代理對象

需要用JDK的Proxy類的newProxyInstance方法:

static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandler h);

在運行時動態生成類,首先要指定類加載器 loader,然後指明對哪些接口——interfaces生成代理類,最後確定生成的代理類最終是調用哪個被代理類的哪些方法——invocationHandler實例——一個調用處理器。

使用代理類的可能場景

  1. 路由對遠程服務的方法調用
  2. 在程序運行期間,將用戶接口事件與動作關聯起來
  3. 爲了調試,跟蹤方法調用

舉個例子

追蹤Arrays.binarySearch方法的查找過程:輸入查找一個給定的key時,經過了幾次比較,每次是同哪個數比較的。
分析:binarySearch方法是JDK的方法,它調用comparable接口的compareTo方法來做比較和查找,我們無法在這個方法裏插入代碼,來做輸出,但是代理可以做到。
代理就是在執行本要做的事情的前後,再做一些其它的事情,來實現代理的功能。

import java.lang.reflect.*;
import java.util.*;

class ComparableProxy implements InvocationHandler
{
	private Object target;

	public IntegerProxy(Object target){
	
		this.target = target;
	}

	public Object invoke(Object p,Method m,Object [] args) throws  Throwable{

		//  在做比較工作前,輸入比較對象信息
		StringBuilder sb = new StringBuilder(this.toString()).append("],[target:").append(target.toString()).append("],[args:").append(Arrays.toString(args));

		System.out.println(sb.toString());
		
		// 調用實際工作的比較方法
		return	m.invoke(target,args);

	}
}

import static java.lang.System.out;
import java.util.*;
import java.lang.reflect.*;

public class Test{

    public static void main(String[] args){
		
		Object [] proxys = new Object[1000];

		for(int i=0;i<1000;i++){
			proxys[i] = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, new ComparableProxy(i+1));
		}

		int key = new Random().nextInt(1000) + 1;

		out.println("key:"+key);

		int result = Arrays.binarySearch(proxys, key);

		out.println("result:"+result);
    }
}
/*
key:780
[target:500],[args:[780]
[target:750],[args:[780]
[target:875],[args:[780]
[target:812],[args:[780]
[target:781],[args:[780]
[target:765],[args:[780]
[target:773],[args:[780]
[target:777],[args:[780]
[target:779],[args:[780]
[target:780],[args:[780]
result:779
*/

代理類是在程序運行過程中創建的。 一旦被創建, 就變成了常規類, 與虛擬機中的任何其他類沒有什麼區別。

所有的代理類都擴展於 Proxy 類。一個代理類只有一個實例域—調用處理器,它定義超類 Proxy 中。 爲了履行代理對象的職責, 所需要的任何附加數據都必須存儲在調用處理器中。 例如, 在上例中, 代理 Comparable 對象時, ComparableProxy 包裝了實際的對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章