一、爲什麼要用代理模式
1).安全考慮:可以屏蔽客戶端直接訪問真實對象;
2).延遲對真實對象的加載,提升系統啓動時間;
3).在代理類中可進行類似AOP編程
二、實用場景(轉)
1) 遠程代理(Remote Proxy)爲一個位於不同的地址空間的對象提供一個本地的代理對象。如果讓你直接coding去調用,你需要處理網絡連接、處理打包、解包等等非常複雜的步驟,所以爲了簡化客戶端的處理,我們使用代理模式,在客戶端建立一個遠程對象的代理,客戶端就象調用本地對象一樣調用該代理,再由代理去跟實際對象聯繫,對於客戶端來說可能根本沒有感覺到調用的東西在網絡另外一端,這實際上就是Web
Service的工作原理。
2) 虛擬代理(Virtual Proxy)如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時纔會被真正創建。
3) 保護代理(Protection Proxy)控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。
4) 智能指引(Smart Reference)取代了簡單的指針,它在訪問對象時執行一些附加操作。
5) Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲到只有在客戶端真正需要時才執行。一般來說,對象的深克隆是一個開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有對象被用到的時候才被克隆。
三、代理模式涉及角色
1) 代理主題接口
2) 真實主題類
3) 代理類
4) 調用端
四、具體實現方法
1) 靜態代理
/**
* @author pengl
* 2014-5-3
* 描述:代理模式的主題接口
*/
public interface IDBQuery {
public String query();
}
/**
* @author pengl
* 2014-5-3
* 描述:真實主題類
*/
public class DBQuery implements IDBQuery {
public String query() {
return "query strings";
}
}
/**
* @author pengl
* 2014-5-3
* 描述:代理類
*/
public class DBQueryProxy implements IDBQuery{
private DBQuery dbQuery = null;
public String query() {
if(dbQuery==null){
dbQuery = new DBQuery();
}
return dbQuery.query();
}
}
/**
* @author pengl
* 2014-5-3
* 描述:客戶端調用
*/
public class Main {
public static void main(String[] args) {
IDBQuery query = new DBQueryProxy();
query.query();
}
}
2) 動態代理
/**
* @author pengl
* 2014-5-3
* 描述:代理模式的主題接口
*/
public interface IDBQuery {
public String query();
}
/**
* @author pengl
* 2014-5-3
* 描述:真實主題類
*/
public class DBQuery implements IDBQuery {
public String query() {
return "query strings";
}
}
/**
* @author pengl
* 2014-5-3
* 描述:代理類[java動態代理]
*/
public class DynamicProxyFactory implements InvocationHandler{
private Object object;
public DynamicProxyFactory(Object obj){
this.object = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/**
* 我們可以在這個封裝的動態代理類裏添加日誌等操作
*/
Logger.getLogger(this.getClass()).warn("開始調用動態代理類");
method.invoke(object, args);
Logger.getLogger(this.getClass()).warn("調用動態代理類結束");
return null;
}
}
/**
* @author pengl
* 2014-5-3
* 描述:客戶端調用
*/
public class Main {
public static void main(String[] args) {
IDBQuery query = new DBQuery(); //被代理類
InvocationHandler ih = new DynamicProxyFactory(query); //初始化代理類
IDBQuery proQuery = (IDBQuery) Proxy.newProxyInstance(query.getClass().getClassLoader(), query.getClass().getInterfaces(), ih);
proQuery.query();
}
}
上面演示的只是JDK自帶的動態代理,還有CGLIB、Javassist、ASM等實現庫。如Hibernate框架中的load查詢,就是使用的CGLIB實現庫。