---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------
代理
生活中的代理:
廣西人從廣西的代理商手中買聯想電腦和直接跑到北京傳智播客旁邊來找聯想總部買電腦,你覺得最終的主體業務目標有什麼區別嗎? 基本上一樣吧,都解決了核心問題,但是,一點區別都沒有嗎?從代理商那裏買真的一點好處都沒有嗎?
程序中的代理:
要爲已存在的多個具有相同接口的目標類的各個方法增加一些系統功能,例如,異常處理、日誌、計算方法的運行時間、事務管理、等 等,你準備如何做?
編寫一個與目標類具有相同接口的代理類,代理類的每個方法調用目標類的相同方法,並在調用方法時加上系統功能的代碼。
如果採用工廠模式和配置文件的方式進行管理,則不需要修改客戶端程序,在配置文件中配置是使用目標類、還是代理類,這樣以後很 容易切換,譬如,想要日誌功能時就配置代理類,否則配置目標類,這樣,增加系統功能很容易,以後運行一段時間後,又想去掉系統 功能也很容易。
要爲系統中的各種接口的類增加代理功能,那將需要太多的代理類,全部採用靜態代理方式,將是一件非常麻煩的事情!寫成百上千個代理 類,是不是太累!
JVM可以在運行期動態生成出類的字節碼,這種動態生成的類往往被用作代理類,即動態代理類。
JVM生成的動態類必須實現一個或多個接口,所以,JVM生成的動態類只能用作具有相同接口的目標類的代理。
CGLIB庫可以動態生成一個類的子類,一個類的子類也可以用作該類的代理,所以,如果要爲一個沒有實現接口的類生成動態代理類,那麼 可以使用CGLIB庫。
代理類的各個方法中通常除了要調用目標的相應方法和對外返回目標返回的結果外,還可以在代理方法中的如下四個位置加上系統功能代 碼:
1、在調用目標方法之前
2、在調用目標方法之後
3、在調用目標方法前後
4、在處理目標方法異常的catch塊中
5、需要寫一個示意代碼進行輔助說明,如:
Class proxy{
void sayHello(){
……….
try{
target.sayHello();
}catch(Exception e){
………..
}
………….
}
}
動態生成的類成爲目標類的代碼:
直接在InvocationHandler實現類中創建目標類的實例對象,可以看運行效果和加入日誌代碼,但沒有實際意義。
爲InvocationHandler實現類注入目標類的實例對象,不能採用匿名內部類的形式了。
讓匿名的InvocationHandler實現類訪問外面方法中的目標類實例對象的final類型的引用變量。
將創建代理的過程改爲一種更優雅的方式,eclipse重構出一個getProxy方法綁定接收目標同時返回代理對象,讓調用者更懶惰,更方便,調 用者甚至不用接觸任何代理的API。
將系統功能代碼模塊化,即將切面代碼也改爲通過參數形式提供,怎樣把要執行的系統功能代碼以參數形式提供?
把要執行的代碼裝到一個對象的某個方法裏,然後把這個對象作爲參數傳遞,接收者只要調用這個對象的方法,即等於執行了外界提供 的代碼!
工廠類BeanFactory負責創建目標類或代理類的實例對象,並通過配置文件實現切換。其getBean方法根據參數字符串返回一個相應的實例 對象,如果參數字符串在配置文件中對應的類名不是ProxyFactoryBean,則直接返回該類的實例對象,否則,返回該類實例對象的getProxy 方法返回的對象。
BeanFactory的構造方法接收代表配置文件的輸入流對象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------