动态代理实现原理

来源:互联网 发布:高压气瓶使用 知乎 编辑:程序博客网 时间:2024/06/06 00:45

Proxy代理

Pro代理模式是一种常见的结构设计模式,主要解决的问题是:在直接访问对象的时候带来的问题。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

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

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

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

Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。

java.lang.reflect.Proxy类中的newProxyInstance方法(也就是创建代理对象的方法):

//CLassLoader loader:类的加载器  //Class<?> interfaces:得到全部的接口  //InvocationHandler h:得到InvocationHandler接口的子类的实例  public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException


java.lang.reflect.InvocationHandler接口中 invoke方法的完整形式如下(实现InvocationHandler接口才能重写invoke方法):

//Object proxy:被代理的对象//Method method:要调用的方法//Object[] args:方法调用时所需要参数public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {          method.invoke(obj, args);          return null;      }

举例说明:

//定义接口:(动态代理只能代理接口)  public interface Subject {            public void request();  }
//实现接口:实现了Subject的request()方法  public class RealSubject implements Subject{            public void request(){          System.out.println("From real subject.");      }  }
//实现了InvocationHandler  public class DynamicSubject implements InvocationHandler {      private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象        public DynamicSubject(){}        public DynamicSubject(Object obj){          this.obj = obj;      }        //这个方法不是我们显示的去调用,而是在我们通过代理对象调用目标对象的目标方法的时候,首先出发invoke方法再通过调用的方法将目标对象中对应方法的方法对象传给invoke进行动态创建方法。     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable      {          System.out.println("before calling " + method);            method.invoke(obj, args);            System.out.println("after calling " + method);            return null;      }    }

//客户端:生成代理实例对象,并调用了request()方法  public class Client {        public static void main(String[] args) throws Throwable{                   Subject rs=new RealSubject();//这里指定被代理类          InvocationHandler ds=new DynamicSubject(rs);          Class<?> cls=rs.getClass();                    //以下是一次性生成代理          //public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException          Subject subject=(Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), ds);          //利用代理对象调用request()方法 System.out.println("运行结果为:");          subject.request();  System.out.println("--------------------------下面是一些验证信息--------------------------"); //这里可以通过运行结果证明subject是Proxy的一个实例,这个实例实现了Subject接口。验证subject是否为Proxy类的一个实例。 System.out.println("\n\n"+subject instanceof Proxy); //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口 System.out.println("subject的Class类是:"+subject.getClass().toString()); System.out.print("subject中的属性有:"); Field[] field=subject.getClass().getDeclaredFields(); for(Field f:field){ System.out.print(f.getName()+", "); } System.out.print("\n"+"subject中的方法有:"); Method[] method=subject.getClass().getDeclaredMethods(); for(Method m:method){ System.out.print(m.getName()+", "); } System.out.println("\n"+"subject的父类是:"+subject.getClass().getSuperclass()); System.out.print("\n"+"subject实现的接口是:");Class<?>[] interfaces=subject.getClass().getInterfaces(); for(Class<?> i:interfaces){ System.out.print(i.getName()+", "); }     } }




运行结果为:
before calling public abstract void ***.
Subject.request() From real subject. 
after calling public abstract void ***.

Subject.request()true 
subject的Class类是:class $Proxy0 
subject中的属性有:m1, m3, m0, m2, 
subject中的方法有:request, hashCode, equals, toString, 
subject的父类是:class java.lang.reflect.Proxy 
subject实现的接口是:cn.edu.ustc.dynamicproxy.Subject,



上面的true和class $Proxy0就能说明代理对象subject继承了Proxy类并实现了Subject接口。

以下是底层源码的实现。

从以上代码和结果可以看出,我们并没有显示的调用invoke()方法,但是这个方法确实执行了下面我们就对invoke的调用时机进行分析。

从Client中的代码看,可以从newProxyInstance这个方法作为突破口,我们先来看一下Proxy类中newProxyInstance方法的源码:


public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException {if (h == null) {throw new NullPointerException();}/* * Look up or generate the designated proxy class. */Class cl = getProxyClass(loader, interfaces);/* * Invoke its constructor with the designated invocation handler. */try {/* * Proxy源码开始有这样的定义: private final static Class[] constructorParams = * { InvocationHandler.class }; cons即是形参为InvocationHandler类型的构造方法 */Constructor cons = cl.getConstructor(constructorParams);return (Object) cons.newInstance(new Object[] { h });} catch (NoSuchMethodException e) {throw new InternalError(e.toString());} catch (IllegalAccessException e) {throw new InternalError(e.toString());} catch (InstantiationException e) {throw new InternalError(e.toString());} catch (InvocationTargetException e) {throw new InternalError(e.toString());}}


Proxy.newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h)做了以下几件事.

(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类.

(2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值



class Proxy{      InvocationHandler h=null;      protected Proxy(InvocationHandler h) {          this.h = h;      }      ...  }


接下来看一下这个继承了Proxy的$Proxy0的源码:



public final class $Proxy0 extends Proxy implements Subject {private static Method m1;private static Method m0;private static Method m3;private static Method m2;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);m3 = Class.forName("***.RealSubject").getMethod("request",new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString",new Class[0]);} catch (NoSuchMethodException nosuchmethodexception) {throw new NoSuchMethodError(nosuchmethodexception.getMessage());} catch (ClassNotFoundException classnotfoundexception) {throw new NoClassDefFoundError(classnotfoundexception.getMessage());}} // staticpublic $Proxy0(InvocationHandler invocationhandler) {super(invocationhandler);}@Overridepublic final boolean equals(Object obj) {try {return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })).booleanValue();} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}@Overridepublic final int hashCode() {try {return ((Integer) super.h.invoke(this, m0, null)).intValue();} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final void request() {try {super.h.invoke(this, m3, null);return;} catch (Error e) {} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}@Overridepublic final String toString() {try {return (String) super.h.invoke(this, m2, null);} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}}


接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即 InvocationHandler.invoke()




0 0
原创粉丝点击