Java動態代理詳解(轉載)

Java動態代理詳解

說到動態代理,顧名思義就是動態的代理(真是廢話)。

關於代理:想必大家都並不陌生,GOF的23種設計模式之一(結構型模式)。這裏暫不多做介紹,有興趣的可以關注我關於設計模式的文章。

什麼是動態代理:

說起動態,其實不如先說什麼是靜態。所謂靜態代理,個人理解爲自己手寫的代理類,或者用工具生成的代理類,或者別人幫你寫的代理類(沒說一樣...)。總之,就是程序運行前就已經存在的編譯好的代理類。

相反,如果代理類程序運行前並不存在,需要在程序運行時動態生成(無需手工編寫代理類源碼),那就是今天要說的動態代理了。

如何生成的:根據Java的反射機制動態生成。

不多說了,上程序。

目標接口TargetInterface:

Java代碼  收藏代碼
  1. public interface TargetInterface {  
  2.     public int targetMethodA(int number);  
  3.     public int targetMethodB(int number);  
  4. }  

很簡單,一個普通的接口,裏面有若干方法(此處寫2個示範一下)

實現該接口的委託類ConcreteClass:

Java代碼  收藏代碼
  1. public class ConcreteClass implements TargetInterface{  
  2.   
  3.     public int targetMethodA(int number) {  
  4.         System.out.println("開始調用目標類的方法targetMethodA...");  
  5.         System.out.println("操作-打印數字:"+number);  
  6.         System.out.println("結束調用目標類的方法targetMethodA...");  
  7.         return number;  
  8.     }  
  9.       
  10.     public int targetMethodB(int number){  
  11.         System.out.println("開始調用目標類的方法targetMethodB...");  
  12.         System.out.println("操作-打印數字:"+number);  
  13.         System.out.println("結束調用目標類的方法targetMethodB...");  
  14.         return number;  
  15.     }  
  16.   
  17. }  

很簡單,一個普通的類,實現了目標接口。

代理處理器類ProxyHandler:

Java代碼  收藏代碼
  1. public class ProxyHandler implements InvocationHandler{  
  2.     private Object concreteClass;  
  3.       
  4.     public ProxyHandler(Object concreteClass){  
  5.         this.concreteClass=concreteClass;  
  6.     }  
  7.   
  8.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  9.         System.out.println("proxy:"+proxy.getClass().getName());  
  10.         System.out.println("method:"+method.getName());  
  11.         System.out.println("args:"+args[0].getClass().getName());  
  12.           
  13.         System.out.println("Before invoke method...");  
  14.         Object object=method.invoke(concreteClass, args);//普通的Java反射代碼,通過反射執行某個類的某方法  
  15.         //System.out.println(((ConcreteClass)concreteClass).targetMethod(10)+(Integer)args[0]);  
  16.         System.out.println("After invoke method...");  
  17.         return object;  
  18.     }  
  19.   
  20. }  

該類實現了Java反射包中的InvocationHandler接口。代理實例調用方法時,將對方法調用指派到它的代理處理器程序的invoke方法中。invoke方法內部實現預處理,對委託類方法調用,事後處理等邏輯。

最後是入口程序:

Java代碼  收藏代碼
  1. public class DynamicProxyExample {  
  2.     public static void main(String[] args){  
  3.          ConcreteClass c=new ConcreteClass();//元對象(被代理對象)  
  4.          InvocationHandler ih=new ProxyHandler(c);//代理實例的調用處理程序。  
  5.          //創建一個實現業務接口的代理類,用於訪問業務類(見代理模式)。  
  6.          //返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序,如ProxyHandler。  
  7.          TargetInterface targetInterface=  
  8.              (TargetInterface)Proxy.newProxyInstance(c.getClass().getClassLoader(),c.getClass().getInterfaces(),ih);  
  9.          //調用代理類方法,Java執行InvocationHandler接口的方法.  
  10.          int i=targetInterface.targetMethodA(5);  
  11.          System.out.println(i);  
  12.          System.out.println();  
  13.          int j=targetInterface.targetMethodB(15);  
  14.          System.out.println(j);  
  15.     }  
  16. }  

首先創建委託類對象,將其以構造函數傳入代理處理器,代理處理器ProxyHandler中會以Java反射方式調用該委託類對應的方法。然後使用Java反射機制中的Proxy.newProxyInstance方式創建一個代理類實例,創建該實例需要指定該實例的類加載器,需要實現的接口(即目標接口),以及處理代理實例接口調用的處理器。

最後,調用代理類目標接口方法時,會自動將其轉發到代理處理器中的invoke方法內,invoke方法內部實現預處理,對委託類方法調用,事後處理等邏輯。

 

使用Java動態代理機制的好處:

1、減少編程的工作量:假如需要實現多種代理處理邏輯,只要寫多個代理處理器就可以了,無需每種方式都寫一個代理類。

2、系統擴展性和維護性增強,程序修改起來也方便多了(一般只要改代理處理器類就行了)。

 

使用Java動態代理機制的限制:

目前根據GOF的代理模式,代理類和委託類需要都實現同一個接口。也就是說只有實現了某個接口的類可以使用Java動態代理機制。但是,事實上使用中並不是遇到的所有類都會給你實現一個接口。因此,對於沒有實現接口的類,目前無法使用該機制。有人說這不是廢話嗎,本來Proxy模式定義的就是委託類要實現接口的啊!但是沒有實現接口的類,該如何實現動態代理呢?

當然不是沒有辦法,這也是我後面抽時間要繼續整理和總結原先使用過的一件神器,相關Blog會不定期發上來。那就是大名鼎鼎的CGLib...

PS:CGLib中的動態代理已經新鮮出爐,歡迎訪問:http://shensy.iteye.com/blog/1873155 


聲明:轉載自 http://shensy.iteye.com/blog/1698197 

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