动态代理是如何工作的?

我们知道,动态代理主要基于 java.lang.reflect 包下的两个类,一个是 InvocationHandler ,一个是 Proxy 。一个简单的 Dynamic Proxy 的构造过程如下:

==================================================

public class MyInvocationHandler implements InvocationHandler {

private Object target;

public void setTarget(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Do something here.
return method.invoke(target, args);
// Do something here.
}
}

public class ProxyGenerator {

public static Object generateProxy(Object target, InvocationHandler h) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), h);
}

}

Hello hello = new Hello();
MyInvocationHandler h = new MyInvocationHandler();
h.setTarget(hello);
Object proxy = ProxyGenerator.generateProxy(hello, h);
IHello iHello = (IHello) proxy;
iHello.sayHello();

==================================================

OK ,这段大家都知道,但 invoke() 方法到底是如何作用到 Proxy 上的呢?
我们可以加上 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
这句话,让生成的 Proxy 字节码存储在硬盘上,然后反编译该字节码,看看动态代理的原理。

观察生成的代理类的源码,我们发现它覆写了接口中的所有方法,以及从 java.lang.Object 中继承过来的方法,如: toString() 、 equals() 、 hashCode() 等。以 sayHello() 方法为例,在代理类中它被覆写成了这个样子:
public final void sayHello() {
// 此处省略虚拟机自动添加的异常处理等
this.h.invoke(this, m3, null);
return;
}

这些方法使用这种统一的格式进行方法调用:
[color=red]this.h.invoke(this, method, args);[/color]
下面来解释一下这句话的各个部分。

this.h: InvocationHandler 的实例。我们知道, Proxy.newProxyInstance() 的时候,把一个 InvocationHandler 实例作为它的第三个参数。事实上在最终生成的 Proxy 中,它持有这个 InvocationHandler 实例,所以能通过 this 引用到。

invoke: 没有任何高深的东西,它就是一个 InvocationHandler 的实例 this.h 对它的实例方法 invoke() 的一次普通调用。换句话说,我们在 InvocationHandler 中覆写的方法在这里被回调了,发挥作用了!我们再来复习一下这个方法的定义:
[color=red]public Object invoke(Object proxy, Method method, Object[] args) throws Throwable[/color]
第一个参数代表 proxy ,在最终生成的 Proxy 实现中就是它自己。
第二个参数代表方法,比如接口中的方法、 toString 、 equals 、 hashCode 等。这些方法将在代理类的静态块中初始化好,比如:
static {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[1] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.test.IHello").getMethod("sayHello", new Class[0]);
}
第三个参数不用解释,代表参数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值