首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

深入研究java中的静态署理和动态代理

2013-09-08 
深入研究java中的静态代理和动态代理java编码中经常用到代理,代理分为静态代理和动态代理。一、静态代理:程

深入研究java中的静态代理和动态代理
java编码中经常用到代理,代理分为静态代理和动态代理。一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了被代理类的公共父类package staticproxy;public abstract class BaseClass {    public abstract void add();}被代理类package staticproxy;public class A extends BaseClass {    public void add() {        System.out.println("A add !");    }}代理类package staticproxy;public class Proxy {    BaseClass baseClass;    public void add() {        baseClass.add();    }    public void setBaseClass(BaseClass baseClass) {        this.baseClass = baseClass;    }    public static void main(String[] args) {        BaseClass baseClass = new A();        Proxy proxy = new Proxy();        proxy.setBaseClass(baseClass);        proxy.add();    }}二、动态代理:实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成被代理类接口package jdkproxy;public interface Service {    public void add();    public void update();}被代理类Apackage jdkproxy;public class AService implements Service {    public void add() {        System.out.println("AService add>>>>>>>>>>>>>>>>>>");    }    public void update() {        System.out.println("AService update>>>>>>>>>>>>>>>");    }}被代理类Bpackage jdkproxy;public class BService implements Service {    public void add() {        System.out.println("BService add---------------");    }    public void update() {        System.out.println("BService update---------------");    }}代理类package jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {    private Object target;    MyInvocationHandler() {        super();    }    MyInvocationHandler(Object target) {        super();        this.target = target;    }    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        // 程序执行前加入逻辑        System.out.println("before-----------------------------");        // 程序执行        Object result = method.invoke(target, args);        //程序执行后加入逻辑        System.out.println("after------------------------------");        return result;    }    public Object getTarget() {        return target;    }    public void setTarget(Object target) {        this.target = target;    }}测试类package jdkproxy;import java.lang.reflect.Proxy;public class Test {    public static void main(String[] args) {        Service aService = new AService();        MyInvocationHandler handler = new MyInvocationHandler(aService);        // Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例        Service aServiceProxy = (Service) Proxy.newProxyInstance(aService                .getClass().getClassLoader(), aService.getClass()                .getInterfaces(), handler);        //由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口        aServiceProxy.add();        System.out.println();        aServiceProxy.update();        // 以下是对B的代理        // Service bService = new BService();        // MyInvocationHandler handler = new MyInvocationHandler(bService);        // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService        // .getClass().getClassLoader(), bService.getClass()        // .getInterfaces(), handler);        // bServiceProxy.add();        // System.out.println();        // bServiceProxy.update();    }}输出结果:before-----------------------------AService add>>>>>>>>>>>>>>>>>>after------------------------------before-----------------------------AService update>>>>>>>>>>>>>>>after------------------------------其中上述标红的语句是产生代理类的关键代码,可以产生一个符合Service接口的代理对象,newProxyInstance这个方法会做这样一件事情,他将把你要代理的全部接口,用一个由代码动态生成的类来实现,该类中所有的接口中的方法都重写为调用InvocationHandler.invoke()方法。下面详细介绍是如何实现代理对象的生成的Proxy的newProxyInstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减下下面public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h) throws    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException      {          if (h == null) {              throw new NullPointerException();          }          //生成指定的代理类        Class cl = getProxyClass(loader, interfaces);          Constructor cons = cl.getConstructor(constructorParams);          // 生成代理类的实例,并把MyInvocationHandler的实例传给它的构造方法,代理类对象实际执行都会调用MyInvocationHandler的invoke方法,所以代理类对象中维持一个MyInvocationHandler引用          return (Object) cons.newInstance(new Object[] { h });      }  其中getProxyClass方法返回代理类的实例Proxy的getProxyClass方法public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException{    //前面省略很多缓存、异常处理、判断逻辑代码,为了使程序更加突出    byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(proxyName, interfaces);    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);    proxyClasses.put(proxyClass, null);    return proxyClass;}下面看ProxyGenerator的generateProxyClass方法,该方法最终产生代理类的字节码文件:public static byte[] generateProxyClass(final String name, Class[] interfaces)     {         ProxyGenerator gen = new ProxyGenerator(name, interfaces);      // 这里动态生成代理类的字节码       final byte[] classFile = gen.generateClassFile();      // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上         if (saveGeneratedFiles) {             java.security.AccessController.doPrivileged(             new java.security.PrivilegedAction<Void>() {                 public Void run() {                     try {                         FileOutputStream file =                             new FileOutputStream(dotToSlash(name) + ".class");                         file.write(classFile);                         file.close();                         return null;                     } catch (IOException e) {                         throw new InternalError(                             "I/O exception saving generated file: " + e);                     }                 }             });         }      // 返回代理类的字节码         return classFile;     }   那么最终生成的代理类到底是什么样子呢,如下(省略了一下equals,hashcode,toString等方法,只展示构造函数和add方法):

  1. public final class $Proxy11 extends Proxy implements Service  
  2. {  
  3.     // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例  
  4.     public $Proxy11(InvocationHandler invocationhandler)  
  5.     {  
  6.         super(invocationhandler);  
  7.     }  
  8.     
  9.     /** 
  10.      * 继承的add方法,重写,调用MyInvocationHandler中的invoke方法
  11.      */  
  12.     public final void add()  
  13.     {  
  14.         try  
  15.         {  
  16.             // 实际上就是调用MyInvocationHandler中的invoke方法  
  17.             super.h.invoke(this, m3, null);  
  18.             return;  
  19.         }  
  20.         catch(Error _ex) { }  
  21.         catch(Throwable throwable)  
  22.         {  
  23.             throw new UndeclaredThrowableException(throwable);  
  24.         }  
  25.     }  
  26. }  
注意:java的jdk中得动态代理有一个限制条件,就是必须要被代理的类基于统一的接口,否则不能够实现。如果必须要使代理突破这个限制,那么可以尝试运用cglib来实现动态代理。cglib能够使方法执行更加高效,但是可能在动态创建类的过程中效率会稍微低一些,缓存该过程生成的类即可。

热点排行