如果創建一個對象需要花費較多的時間,做較多的工作,同時還不確定後面會不會實際用上,如你在超市買手機,就給一個模型給你看就得了,你確定要的時候纔去拿一個真機器來給你,這裏這個手機模型可以看作是手機的一個代理。還有現在的藝人都會有經紀人,大部分事情你跟他的經紀人聯繫就搞定了,在登臺演出的時候,經紀人自然會安排藝人Live Show。這裏經紀人就是藝人的一個Proxy。同時在Proxy這裏還可以做一個權限控制,做一層過濾,如在經紀人這裏,看你拿不出100W,根本就不會安排藝人演出,藝人也根本就不知道你這個事情,在打印機那裏,在打印的時候,也可以做一個權限控制,只有在你具有打印機的操作權限時纔會讓你打印。權限驗證沒有通過,打印機對象根本就不會生成。JLive的Forum就使用Proxy進行了權限控制。
打印機程序實例,在真正需要打印的時候才生成打印機對象:
/**
*@(#)Printable.java1.02007-10-23
*/
package pattern.proxy;
/**
*@authortsimgsong
*
*/
publicinterface Printable {
/**
*Nameprinter
*@paramname
*/
publicvoid setPrinterName(String name);
/**
*getPrinterName
*@return
*/
public String getPrinterName();
/**
*printcontent
*@paramcnt
*/
publicvoid print(String cnt);
}
/**
* @(#)Printer.java 1.0 2007-10-23
*/
package pattern.proxy;
import org.apache.log4j.Logger;
/**
* @author tsimgsong
*
*/
public class Printer implements Printable {
private String name;
static Logger logger = Logger.getLogger(Printer.class);
public Printer(){
logger.info("Initializing Printer begin ...");
logger.info("Initialize Printer end ");
}
public Printer(String name){
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String cnt) {
logger.info("Print Begin");
logger.info("Print End");
}
public void setPrinterName(String name) {
this.name = name;
}
}
/**
* @(#)PrinterProxy.java 1.0 2007-10-23
*/
package pattern.proxy;
/**
* @author tsimgsong
*
*/
public class PrinterProxy implements Printable {
private String name ;
private Printer printer;
public PrinterProxy(){
}
public PrinterProxy(String name){
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String cnt) {
realPrinter();
printer.print(cnt);
}
public synchronized void setPrinterName(String name) {
if(printer != null){
printer.setPrinterName(name);
}
this.name = name;
}
private synchronized void realPrinter(){
if(printer == null){
printer = new Printer(name);
}
}
}
如對打印機的使用進行權限控制,就不要客戶端直接生成Printer對象,要打印都通過PrinterProxy來打印,在打印的地方對客戶端權限進行判定。
public void print(PrintPermission permission,String cnt) throws PrintException,UnauthorizedException {
if(permission.canPrint()){
realPrinter();
printer.print(cnt);
}else{
Throw new UnauthorizedException();
}
}
使用Java提供的動態代理:(JAVA提供了一個Proxy類和一個InvocationHandler,這兩個類都在java.lang.reflect包中。程序員通過實現java.lang.reflect.InvocationHandler接口提供一個執行處理器,然後通過java.lang.reflect.Proxy得到一個代理對象,通過這個代理對象來執行方法,方法被調用的同時,執行處理器會被自動調用。)
package pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*@authortsimgsong
*
*/
publicclass DynamicProxy implements InvocationHandler{
private Object original;
public DynamicProxy(Object orig){
this.original = orig;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//這裏可以加上權限控制
Object obj = method.invoke(original, args);
return obj;
}
publicstaticvoid main(String args[]){
Printer pp = new Printer();
DynamicProxy dp = new DynamicProxy(pp);
Printable p = (Printable)Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{Printable.class}, dp);
p.print("ddddd"); }
}
程序首先創建一個被代理對象然後初始化代理對象,最後由Proxy的newProxyInstance獲得一個代理實例, newProxyInstance方法有三個參數, ClassLoader, Class[] interfaces, InvocationHandler。ClassLoader是當前的類加載器,interfaces是代理實例要實現的接口的類(需要指出java的Proxy是針對接口的,如果傳入的Class類型不是接口,會拋出IllegalArgumentException異常)。InvocationHandler則是我們寫的代理處理器。newProxyInstance獲得的實例對象的類是通過修改java二進制文件來獲得的,Proxy中有一個private static native Class defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);方法,這個本地方法實現了這個Class的生成,至於具體的實現我們無法看到,不過很多資料上都有關於native方法的討論。
Ref:
2、 http://boool.blogdriver.com/boool/284115.html