為什麼我們需要動態代理
什麼是代理?你可以理解為現實中的中介,比如房地產中介。你需要買套二手房,過戶那個手續是需要自己做的,其餘什麼跟房東協商跑腿之類的工作交給中介去做,那麼這個中介就是你的代理了。用代碼來展示這個過程就是:
//買房的接口
public interface HouseService {
public void buy () ;
}
//你自己
public class You implements HouseService {
public void buy () {
System.out.println( “房產過戶” );
}
}
//房地產中介
public class Proxy implements HouseService {
private You you;
public Proxy (You you) {
this .you = you;
}
public void buy () {
System.out.println( “跟房東溝通扯淡” );
you.buy();
System.out.println( “交完房跟房東喝酒繼續扯淡,不關我的事了” );
}
}
代碼很簡單而又似曾相識,就是自己做核心的實際,其它雜事交給其他人來做。這話聽起來是不是有點熟悉,你猜對了,這就是AOP。那麼動態代理又是怎樣的,為什麼會存在動態代理?且讓我再舉個例子:
比如我們去商業中心吃個飯,我們需要開車過去,吃完飯,開車回來:
public interface EatingService {
public void eating () ;
}
public class YouEating implements EatingService {
public void eating () {
System. out .println( “和女朋友吃飯” );
}
}
public class EatingProxy implements EatingService {
public void eating () {
System. out .println( “開車去” );
System. out .println( “和女朋友吃飯” );
System. out .println( “開車回” );
}
}
好,上周和女朋友吃飯去了,這周要和女朋友去釣魚:
public interface FishingService {
public void fishing () ;
}
public class YouFishing implements FishingService {
public void fishing () {
System. out .println( “和女朋友釣魚” );
}
}
public class FishingProxy implements FishingService {
public void fishing () {
System. out .println( “開車去” );
System. out .println( “和女朋友去釣魚” );
System. out .println( “開車回” );
}
}
發現問題了沒有?無論跟女朋友去吃飯,去釣魚或者去看電影什麼的,我都要開車去開車回,我不得不為每件事情都添加一個代理類。可想而知,針對每件事情都新建一個代理類,馬上就類爆炸了,代碼潔癖的人絕對會瘋掉。動態代理就在這種情況下出現了,現在大概能知道動態代理解決的是什麼問題了吧?
現在寫個動態代理解決上面的問題,我們寫一個動態代理類來為每件事情加入開車去和開車回兩個動作:
public class CarHandler implements InvocationHandler {
private Object realObject;
public CarHandler( Object realObject) {
this .realObject = realObject;
}
public Object invoke( Object proxy, Method method, Object [] args) throws Throwable {
System.out. println ( “開車去” );
method.invoke(realObject, args);
System.out. println ( “開車回” );
return null ;
}
}
好,現在上面這個調用處理器幫我們為每件事情都加入了開車去和開車回兩個動作,那麼我們要怎麼用呢?我們寫個測試類看一下:
//和女朋友一起愉快地玩耍測試類
public class DoWithGFTest {
public static void main( String [] args) {
System .out.println( “———-測試吃飯動態代理———–“ );
//實際吃飯
EatingService eating = new YouEating ();
//開車去開車回動作
CarHandler eatCarHanlder = new CarHandler (eating);
//吃飯代理
EatingService dynamicEatingProxy = ( EatingService ) Proxy . newProxyInstance (eating.getClass(). getClassLoader (),
eating . getClass (). getInterfaces (), eatCarHanlder );
dynamicEatingProxy . eating ();
System . out . println (“———-測試釣魚動態代理———–“);
FishingService fishing = new YouFishing ();
CarHandler fishCarHanlder = new CarHandler (fishing);
FishingService dynamicFishingProxy = ( FishingService ) Proxy . newProxyInstance (fishing.getClass(). getClassLoader (),
fishing . getClass (). getInterfaces (), fishCarHanlder );
dynamicFishingProxy . fishing ();
}
}
輸出:
———-測試吃飯動態代理———–
開車去
和女朋友吃飯
開車回
———-測試釣魚動態代理———–
開車去
和女朋友釣魚
開車回
好吧,現在你可以把吃飯代理EatingProxy和釣魚代理FishingProxy這兩個類刪掉了,我們只需要CarHandler就足夠了,動態代理可以為你需要的每件事情都加入開車去和開車回兩個動作了。
現在,我們回想一下,在我們所以的框架中那些地方用上了動態代理?日誌,遠程通信,緩存,訪問控制這些是不是都有?剩下的讀者自己想像挖掘了。