使用JDK API实现动态代理和源码分析

讨论和学习JDK API 实现动态代理,源码分析

前置知识

  • 了解类是由属性和方法构成
  • 了解Java可以动态定义类信息
  • 了解反射

基本概念:

动态代理:为实现某个接口的原始类(被代理类),在运行时动态生成代理对象
代理:在被代理之前的,代理被代理的
被代理:需要代理协助的对象

逻辑推理/猜想

1.代理被代理之间要有关联
2.对外展示的功能是一样。
3.再想想具体的Java实现

通过什么手段能为一个类或者接口动态生成代理 ?

  1. 对象是由类生成,所以先需要生成类,在生成对象,
  2. 是由属性方法构成,这里重点关注方法,那我们我们生成的类,应该具备哪些方法呢? 因为代理和被代理对外是一致的,所被代理有哪些方法,那代理也就有哪些方法,所以我们就可以生成类,接着就可以生成代理对象。

代码演示

  1. 定义代理和被代理类都需要实现的接口
public interface ITest {
    void test();
}

被代理实现接口

/**
 * 被代理
 * @Author: malone
 * @Date 2020/6/26 23:08
 */
public class Represented implements ITest {
    @Override
    public void test() {
        System.out.println("Represented method invocation");
    }
}
  1. 根据JDK创建代理对象的方法需要,实现InvocationHandler接口
/**
 * @Author: malone
 * @Date 2020/6/26 23:09
 */
public class DynamicInvocationHandler implements InvocationHandler {
    // 被代理对象
    private Object object;

    public DynamicInvocationHandler(Object object){
        this.object = object;
    }
    // 方法调用拦截
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke proxy method");
        method.invoke(object,args); // 调用被代理方法,通过反射方法
        return null;
    }
}
  1. 调用public static Object newProxyInstance()创建代理对象
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

loader:当前被代理对象使用的类加载器
interfaces:需要实现接口数组
h: 第2步实现了InvocationHandler接口的对象

下面是动态代理DynamicProxy的测试,通过newProxyInstance方法,创建代理对象proxy,在代理对象上调用和被代理对象相同的方法,我们看到,代理对象和被代理对象的信息都输出了。

/**
 * @Author: malone
 * @Date 2020/6/26 23:11
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
        System.getProperties().setProperty(property ,"true");
        // 以上两句话用于保存,JDK动态产生的代理类Proxy0
        ITest represented = new Represented();  // 被代理实例
        ITest proxy = (ITest)Proxy.newProxyInstance(represented.getClass().getClassLoader(),
                represented.getClass().getInterfaces(),new DynamicInvocationHandler(represented));
        proxy.test(); // 通过代理调用方法
    }
}

下面是输出

invoke proxy method
Represented method invocation

源码

  String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
  System.getProperties().setProperty(property ,"true");

上面两个代码将保存生成的代理类$Proxy0到本地.我,我们打开看看。

生成类所在位置
动态生成所类

public final class $Proxy0 extends Proxy implements ITest {

生成的类继承了Proxy类,实现了ITest类,这也就保证了和被代理一致的行为。至于继承Proxy类是为了调用InvocationHandler中的Invoke方法,也就是我们实现代理逻辑的方法。如下所示,我们主要看ITest中定义的方法test在生成类中的实现。

    public final void test() throws  {
        try {
        	// 调用父类Proxy中的InvocationHandler的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

总结

  1. 逻辑中涉及代理对象和被代理对象两个角色
  2. 实现中,涉及接口定义、代理的定义(InvocationHandler 接口实现)、代理的创建Proxy.newProxyInstance方法的调用
  3. 涉及反射知识:被代理类的方法调用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章