一篇文章将懂动态代理

196 阅读2分钟

一句话总结:

动态代理是通过根据Interface通过ProxyFactory生成$Proxy*InterfaceName代理类实现的。

简单说明:

  • interface提供接口,以此为根据,通过工厂模式,生成对应Proxy类
  • 最终调用是调用$Proxy*InterfaceName的方法
  • $Proxy*InterfaceName又调用的InvocationHandler的invoke方法

实现原理

所谓动态代理,其实就是在编译期,通过Factory生成目标接口相对应的代理类,命名为$Proxy{动态number}{相关的接口名},该实现了相关接口,集成了Proxy类,Proxy类中持有InvocationHandler的具体实例。

所以我们拿到代理实例后,调用了代理实例实现的Interface的方法,该方法内部有调用了Proxy中持有的持有某个具体实现的InvocationHandler的invoke方法。

很简单吧。

Interface接口

把我们想要代理的操作抽象成接口,然后Proxy.newProxyInstance方法会通过Factory创建该接口具体代理类。

interface Phone {
    void info();
}

当前例子中,Proxy.newProxyInstance方法会通过工厂Factory创建Phone的代理类。

具体实例

接口对应的具体实例,即需要被代理的具体实现

import com.xiaoyang.Phone;
class HuaWei implements Phone {
    public void info() {
        // 具体实现
        System.out.println("HuaWei");
    }
}

在Proxy.newProxyInstance生成Interface具体代理类的时候,该具体实现会被创建出InvocationHandler的实例中持有,InvocationHandler中invoke方法被调用后反射的主体就是它。InvocationHandler被创建出来的代理类持有,当代理方法被调用后,InvocationHandler.invoke方法会被调用。

InvocationHandler实现类

import java.lang.reflect.InvocationHandler;
class ProxyHandler extends InvocationHandler {
    // 这里持有了具体实现
    private Object object;

    public ProxyHandler(Object impl) {
        this.object = impl;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 添加了某些操作
        System.out.println("Call: " + object.getClass().getSimpleName() + "." + method.getName());
        return method.invoke(object, args);
    }
}

该类持有具体的某个实现,它会被Factory生成的代理类所持有,当调用代理类的某个方法时,最终就会调用到该类的invoke方法,通过反射就调用了具体实现的某个方法。

Proxy.newProxyInstance

通过该方法创建出某interface的具体代理类。

ProxyHandler handler = new ProxyHandler(new IPhone());
Phone phone = (Phone) Proxy.newProxyInstance(IPhone.class.getClassLoader(), IPhone.class.getInterfaces(), handler);
phone.info();

加深理解

什么是动态代理?哪里动态了?

什么是动态代理?

相对于静态代理,需要手动为每一个类创建代理类,动态代理只需要声明好相应接口和对应的InvocationHandler实例就可以通过Proxy.newProxyInstance创建出相应的代理类。

哪里动态了?

哪里动态了,你看编译后的代码,其实就没有什么动态,就是静态代理类,只是通过工厂模式替你写好了相关的代理类而已。要说动态,唯一动态的地方是InvocationHandler的实现,invoke方法中通过反射可以调用任意实例的相关方法。

总结

以某实例为参数创建InvocationHandler的实例,以InvocationHandler和Interface为参数,Proxy.newProxyInstance通过Factory创建出相应的代理类并创建出实例,代理类实例调用的方法都是实现了interface的方法。当代理类调用了某方法时,就是调用了内部InvocationHandler实例的invoke方法,InvocationHandler的invoke方法除了调用自身的某些逻辑外还通过反射调用了具体实例的对应方法。