Proxy模式與Dynamic Proxy實現

Proxy模式與Dynamic Proxy實現

在Spring中,事務管理機制是一個十分重要的特性。也是Spring框架出彩之處。而事務管理機制就是通過Dynamic Proxy和CGLIB兩種方式實現的。在這裏,我先介紹一下Proxy模式和Dynamic Proxy的實現


首先、Proxy模式是GoF的23種設計模式中的一種,稱爲代理模式。由於本人接觸設計模式的時間並不長,對模式的理解可能有所偏差。這裏引用Jdon上的一篇文章對Proxy加以說明。
http://www.jdon.com/designpatterns/designpattern_proxy.htm

在這裏,我順便加上我的一點看法,僅供參考之用。
我認爲,代理模式並不難理解,就像在公司上網,一般都有個代理服務器。這個代理服務器先攔截所有的請求,然後做權限控制處理,再把請求發到Internate上。


其次、說說Dynamic Proxy的實現。動態代理的實現並不複雜,JDK 1.3以後的版本都提供了Proxy來獲取動態代理對象。所以這裏不特別說明。只把代碼貼出來。

首先是一個接口。

public interface TestInterface {
 public void save();
 public void load();
}

接下來是一個實現了上面那個接口的實例類(這個類是需要被代理的類)

public class TestImp implements TestInterface{
 public void load() {
  // TODO Auto-generated method stub
  System.out.println("TestImp load() method");
 }
 
 public void save() {
  // TODO Auto-generated method stub
  System.out.println("TestImp save() method");
 }
}

實例類必須實現某個接口,可以是任意接口,但是必須至少實現一個。因爲以下這行代碼
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    obj.getClass().getInterfaces(), this);
的作用是創建一個代理對象,這個代理對象是由JVM自動創建,並且實現了obj也就是實例對象所實現的所有接口。如果實例對象沒有實現任何接口,這行代碼就會拋出異常。

再來是調用處理程序,也就是需要附加到實例對象上的程序

public class DynamicProxy implements InvocationHandler{

 Object target ;
 
 public Object init(Object obj){
  this.target = obj;
  return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    obj.getClass().getInterfaces(), this);
 }
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  // TODO Auto-generated method stub
  Object result = null;
  try{
   if(method.getName().startsWith("save")){
    System.out.println("before real save in Proxy");
    result = method.invoke(target, args);
    System.out.println("after real save in Proxy");
   }else if(method.getName().startsWith("load")){
    System.out.println("no save method");
    result = method.invoke(target, args);
   }
  }catch(Exception e){
   System.out.println("error in DynamicProxy");
  }
  return result;
 }
}

然後是一個Factory,用於獲取實例對象和代理對象

public class DynamicProxyFactory {
 public static Object getClassInstance(String cn){
  Object result = null;
  try{
   result = Class.forName(cn).newInstance();
  }catch (Exception e) {
   // TODO: handle exception
   System.out.println("error in DynamicProxyFactory 1");
  }
  return result;
 }
 
 public static Object getProxyInstance(String cn){
  Object result = null;
  DynamicProxy proxy = new DynamicProxy();
  try{
   result = proxy.init(Class.forName(cn).newInstance());
  }catch (Exception e) {
   // TODO: handle exception
   System.out.println("error in DynamicProxyFactory 2");
  }
  return result;
 }
}

最後,就是主調方法了

public class MainClass {
 public static void main(String[] args) throws Throwable{
  Object target = DynamicProxyFactory.getClassInstance("com.neusoft.apps.instance.TestImp");
  Object proxy = DynamicProxyFactory.getProxyInstance("com.neusoft.apps.instance.TestImp");
  InvocationHandler obj = Proxy.getInvocationHandler(proxy);
  Method[] method = target.getClass().getMethods();
  for(int i = 0 ;i<method.length;i++){
   obj.invoke(proxy, method[i], null);
  }
 }
}

雖然這個方法比較簡單,但是大家需要注意以下這行代碼:
InvocationHandler obj = Proxy.getInvocationHandler(proxy);
這行代碼是獲取代理對象上的處理程序的引用(JDK上這樣說的,我也讀不明白)。大家可能注意到在DynamicProxy中的init方法裏有以下代碼:
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    obj.getClass().getInterfaces(), this);
這個代碼是創建了代理對象。請注意,這個方法最後的一個參數是this。而:
InvocationHandler obj = Proxy.getInvocationHandler(proxy);
這行代碼獲取的obj就是上面的this。這個處理程序的引用,我們可以調用DynamicProxy中的處理方法invoke。

OK,已完成。 

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