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

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