Java动态代理的总结

vdhn1319 8年前

来自: http://www.cnblogs.com/maybo/p/5193843.html

最近和一个好友在聊起Mybatis时,他问用Mybatis我们只是配置好mapper,然后写dao层接口就实现了dao层方法。然后我说我觉得用动态代理可以实现。然后他又说感觉动态代理和外观模式没什么区别,我说:用动态代理模式时你想在一些代理服务器如Magent(给memcached)提供代理服务时,你调用memcached的接口和Magent,在如你用Nginx做代理服务器时,访问Ngix的http的url并没有因为用了代理服务器就发生变化,所以我说代理模式和外观有一个很明显区别是代理模式接口和需要代理的服务接口一样而且代理模式并不做处理,处理还是需要代理的服务,例如在用Magent他只是做了一些服务器备份,以及路由,负载均衡的处理,而实际的命令还是交给memcached来执行。进天闲暇时间就来总结一下代理模式,以及jdk,cglib代理模式用法,来理解代理模式。

一. JAVA的动态代理(比较官方说法)

代理模式 

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处 理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。 代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的 对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提 供特定的服务。 

按照代理的创建时期,代理类可以分为两种。 

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 

动态代理:在程序运行时,运用反射机制动态创建而成。

二. 动态代理实现

java.lang.reflect.Proxy,

Proxy 提供用于创建动态代理类和实例的静态方法.

newProxyInstance()

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

2.1. Dao接口(提供模拟数据访问层接口)

package javaproxy;  /*   * @author:maybo   *    * @time:2016/2/16   *    * 定义一个数据访问层接口   */  public interface Dao {      //模拟数据保存  public void save();  }

2.2. DaoImpl类实现类

package javaproxy;    public class DaoImpl implements Dao{     @Override   public void save() {    System.out.println("执行一个保存方法。。。。。。。。。。。。");       }    }

2.3. 代理处理类

package javaproxy;    import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;    public class DaoHandler implements InvocationHandler{   private Object obj;  public DaoHandler(Object obj) {   this.obj=obj;  }   @Override   public Object invoke(Object proxy, Method method, Object[] args)     throws Throwable {     System.out.println("do something before method");//这里模拟AOP的前置方法       Object ret = method.invoke(this.obj, args);       System.out.println("do something after method");//这里模拟AOP的后置方法       return ret;   }    }

2.4. client调用

package javaproxy;    import java.lang.reflect.Proxy;    public class Client {         public static void main(String[] args) {       // 元对象(被代理对象)       DaoImpl daoImpl = new DaoImpl();            // 业务代理类      DaoHandler daoHandler=new DaoHandler(daoImpl);          Dao dao=(Dao) Proxy.newProxyInstance(daoImpl         .getClass().getClassLoader(), daoImpl.getClass()         .getInterfaces(), daoHandler);            dao.save();     }  }

2. 5. 结果

3. 模拟Mybatis中的代理实现

3.1. MapperProxy类

package javaproxy;    import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.lang.reflect.Proxy;    public class MapperProxy implements InvocationHandler {      @SuppressWarnings("unchecked")      /*       * 这里通过静态方法得到实现类的对象       *        * @param:接口       *        * @param:用sqlsession执行方法       *        * @return: 返回代理对像       */      public static <T> T newMapperProxy(Class<T> mapperInterface,              Object sqlSession) {          ClassLoader classLoader = mapperInterface.getClassLoader();          Class<?>[] interfaces = new Class[] { mapperInterface };          MapperProxy proxy = new MapperProxy();          return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);      }        /*       * (non-Javadoc)       *        * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,       * java.lang.reflect.Method, java.lang.Object[])       *        * @param:代理对象       *        * @param:方法通过方法名字找到对应的方法       *        * @param:通过方法传入对象找到对应的传递参数映射       *        * @return:返回执行后的参数对象       */      public Object invoke(Object proxy, Method method, Object[] args)              throws Throwable {          // 这里通过方法名字以及参数通过解析对应的mapper来执行对应的操作          System.out.println("在这里执行实际方法");          return null;      }    }

3.2. Client

package javaproxy;    import java.lang.reflect.Proxy;    public class Client {         public static void main(String[] args) {         Dao dao=MapperProxy.newMapperProxy(Dao.class, null);    dao.save();     }  }

3.3. 结果

以上是使用JDK动态代理的例子。至于使用cglib的例子在spring基础说明中有介绍。

</div>