动态代理技术的实现与理解

​ 最近在看《深入理解java虚拟机 –JVM高级特性与最佳实战》这本书,看到动态代理这个部分,虽然以前学习spring的时候就学过动态代理的知识,但是这次看到,突然感受到了不一样的理解,特此分享出来,请大家多多指教。

​ 动态代理实现小例子:

package ObjectCreate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {

interface IHello{
    void sayHello();
}

static class Hello implements IHello{

    @Override
    public void sayHello() {
        System.out.println("hello World");

    }

}

static class DynamicProxy implements InvocationHandler{

    Object originalObj;

    Object bind(Object originalObj){
        this.originalObj = originalObj;
        //通过该方法创建该对象的接口的代理对象的实例
        //步骤2
        Object obj = Proxy.newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
        return obj;
    }

    //步骤5
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("welecome!");
        //通过反射调用实例的方法
        return method.invoke(originalObj, args);
    }

}

public static void main(String[] args) {
    //步骤1
    IHello hello = (IHello) new DynamicProxy().bind(new Hello());
    //步骤3
    hello.sayHello();
}

}

执行结果:

这里写图片描述

分析:上述代码中,唯一的“黑匣子”就是Proxy.newProxyInstance()方法,除此之外再没有任何特殊之处。这个方法返回了一个实现IHello的接口,并且代理了new Hello()实例行为的对象。跟踪这个方法的源码,可以看到其在运行时动态的生成一个描述代理类的字节码byte[] 数组,在main方法中加入下面这段代码可以在磁盘中生成该代理类的class文件:$proxy().class。

System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”,”true”);

将该类进行反编译得到以下代码:

package ObjectCreate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public class $Proxy0 extends Proxy implements DynamicProxyTest.IHello{


private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;

protected $Proxy0(InvocationHandler h) {
    super(h);
}

@Override
public final void sayHello(){
    try{
        //步骤4
        this.h.invoke(this,m3,null);
        return;
    }catch(RuntimeException localRuntimeException){
        throw localRuntimeException;
    }catch(Throwable localThrowable){
        throw new UndeclaredThrowableException(localThrowable);
    }
}
//此处由于版面原因,忽略equals()、hashCode()、toString()、三个方法的代码
//这三个内容与sayHello()方法非常相似。
static {
    try{
        m3 = Class.forName("org.fenixsoft.bytecode.DynamicProxyTest$IHello").getMethod("sayHello", new Class[0]);
        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]);
        m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    }catch(NoSuchMethodException localNoSuchMethodException){
        throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }catch(ClassNotFoundException localClassNotFoundException){
        throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
}

}

以上全是书中写的,以下,为我自己的理解:
代码执行关键步骤:
1、IHello hello = (IHello) new DynamicProxy().bind(new Hello());
分析:该行代码将Hello的实例传递给DynamicProxy对象,返回IHello接口类型的对象($Proxy0这个类的实例)。

2、Object obj = Proxy.newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
分析:该代码在程序运行时动态的生成了$Proxy0这个类的字节码,如以上代码所示,这个类实现了IHello接口的sayHello()方法。
注意:这个方法返回值是$Proxy的实例对象,所以步骤1接受的是这个。

3、hello.sayHello();
分析:通过以上分析,我们可以很明确的理解此sayHello()方法应该是$Proxy的实例中的sayHello()方法。

4、this.h.invoke(this,m3,null);
分析:this表示当前方法所属实例对象、即$Proxy的实例,this.h是父类Proxy中保存的InvocationHandler实例变量也就是DynamicProxy 这个类的实例,事实上该段代码就是调用DynamicProxy 类的invoke方法,传递的参数为sayHello()方法。

5、public Object invoke(Object proxy, Method method, Object[] args)
分析:打印“welecome”语句,然后调用Hello实例的sayHello()方法,打印“hello World” 语句!分析完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值