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,已完成。