动态代理

来源:互联网 发布:中国人工智能技术发展 编辑:程序博客网 时间:2024/05/21 21:38

一、引言
动态代理在运行期生成代理类,为什么要用动态代理设计模式? 因为真实类的接口有可能改变,如果使用静态代理会增加后期的维护成本,当然这只是其中的一个原因。

二、真实类与代理类

2.1 真实类

public class RealObject implements RealInterface{@Overridepublic void doSomething() {System.out.println("真实类做了一些事情");}@Overridepublic void doEleseSomething() {System.out.println("真实类做了一些其他事情");}}
2.2 代理类(这个知识预期生成的代理类)

public class ProxyObject{    private static doSomething m1;          private static doEleseSomething m2;    private  realObject r;    private ProxyObject(realObject r) {            this.r=r;    }    public final void doSomething () throws  {         Method.invoke(ro,m1);    }      public final void doEleseSomething() throws  {         Method.invoke(ro,m2);    }
2.3 JVM 在运行期真实生成的动态代理类

public final class $Proxy0 extends Proxy implements HelloWorld {    private static Method m1;           //基于真实类的接口,经过反射,生成了真实类已经实现了方法    private static Method m3;    private static Method m2;    private static Method m0;    public $Proxy0(InvocationHandler var1) throws  {    //将InvocationHandler 当做参数传入        super(var1);    }    public final void sayHello() throws  {//当用代理类访问次方法的时候,就能对应的知道真实类方法m3        try {            super.h.invoke(this, m3, (Object[])null);   //Proxy 持有InvocationHandler对象,可以调用invoke        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }........................


从2.3JVM生成的真实代理类可以看出,想要生成代理类,代理类必须实现真实类的所有方法,即真实类和代理类采用相同的接口,所以必须给代理类传入真实类实现的接口数组,重点重点重点!!!

三、如何动态生成代理类

动态生成代理的是三要素:真实类、调用处理类、利用Proxy.newProxyInstance生成代理类

3.1 真实类:实现了 RealInterface接口

public class RealObject implements RealInterface{@Overridepublic void doSomething() {System.out.println("真实类做了一些事情");}@Overridepublic void doEleseSomething() {System.out.println("真实类做了一些其他事情");}}
3.2 调用处理类:实现InvocationHandler接口,重现invoke方法

public class DynamicProxyHandler implements InvocationHandler {private RealObject real;public DynamicProxyHandler(RealObject real) {this.real=real;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//proxy:真实对象  method:真实对象的方法, Object:真实对象的方法所需要的参数return method.invoke(real, args);}}
这个类两个作用:1)持有真实类的引用 2)invoke根据传入的Method参数,直接调用真实类的method方法。

3.3 利用Proxy.newProxyInstance生成动态代理类

public static void main(String[] args) throws NoSuchMethodException, SecurityException, Throwable {RealObject real=new RealObject();     //生成真实类InvocationHandler handler=new DynamicProxyHandler(real); //代理类持有真实类RealInterface iReal=(RealInterface) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), real.getClass().getInterfaces(), handler);iReal.doSomething();}

注:Proxy.newProxyInstance方法有三个参数:第一个参数是类加载器对象(即哪个类加载器来加载这个代理类到 JVM 的方法区),第二个参数是接口(表明你这个代理类需要实现哪些接口),第三个参数是调用处理器类实例(指定代理类中具体要干什么)。
传入第二个参数使得2.3所动态生成的代理类与真实类实现同样的接口,即有同样的方法。
传入第三个参数使得2.3所动态生成的代理类的每个方法都可以通过以下方式调用:

 super.h.invoke(this, m3, (Object[])null);

其中的h就代表传入的第三个参数,h.invoke其实就是在调用3.2中的invoke方法
四、动态代理的过程
1、根据3.3生成如2.3的代理类
2、执行以下方法,就相当于抵用2.3代理类相应的doSometing()方法

iReal.doSomething()

3、2.3代理类的doSometing()方法会执行以下代码

其中m3会根据你调用的方法动态生成Method dosomething这个实例

super.h.invoke(this, dosomething, (Object[])null);

4、最后实际调用3.2调用处理类的invoke方法
5、invoke方法动态抵用真实类的dosomething(),返回结果
以上是整个动态代理的过程,以前看了几次,每次都有新的体会,这次就写下来分享一下,如有错误,请指正批评!
最后说一句,如果真实类没有实现任何接口(只有真实类自己的方法),按照以上叙述,就无法动态生成方法,答案是:JVM会采用CGLIB生成代理类






原创粉丝点击