JDK动态代理实现原理详细分析

在之前Java代理模式中大致的分析了下代理模式的类型及对每种代理类型简单的举例了下。本文将对JDK动态代理进行详细的分析。读完本文,你将对JDK的动态代理的运行流程,生成的代理类结构以及实现的原理有一个更加深入的认识。

本文将从以下几个方面概述:

目录

一:JDK动态代理简单样例

二:JDK动态代理生成的代理类分析

三:JDK动态代理运行流程分析

四:JDK动态代理源码分析


一:JDK动态代理简单样例

这里我们还是从一个小例子入手:

//获取(不同国家人)说什么语言的接口
public interface Person {
    String getSpeakLanguage();
}


//两个实现类 分别为 说中文 和 说英文
public class PersonA implements Person {
    public String getSpeakLanguage() {
        return "说中文";
    }
}
public class PersonB  implements Person {
    public String getSpeakLanguage() {
        return "说英文";
    }
}

/**
 * 代理类
 */
public class PersonProxy implements InvocationHandler {
    private Object target;

    public Object getInstance(Object target){
            this.target =target;
        Class<?> clazz = target.getClass();
        /**
         * 三个参数为:目标类加载器,目标类实现的接口  代理类本省
         */
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //实际执行方法的地方
        Object result = method.invoke(target, args);
        return result;
    }
}

//测试类
public static void main(String[] args) {
        Person instance = (Person) new PersonProxy().getInstance(new PersonA());
        //instance实际上已经是生成的代理的对象了,而不是之前的(PersonA)对象了
        System.out.println(instance.getClass());  // com.sun.proxy.$Proxy0
        System.out.println(instance.getSpeakLanguage());
}

这里需要注意的几点是:

1:JDK代理是基于接口的,可参考Java代理模式。即接口是实现JDK代理的基础。

2:Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this) 第三个参数为代理者本身,本样例中即为  PersonProxy对象。

3:method.invoke(target, args) 执行的时候,target为具体的目标类对象而不是生成的代理类对象。在样例中切记不能写为method.invoke(proxy, args)。即不要写为代理类的方法,否则会造成死循环的问题(这里在下文会分析)。注: target 为目标类对象,即本文中的PersonA 和PersonB对象。proxy为JDK为我们生成的动态代理的对象。

4:在测试类中通过动态代理类生成的对象已经是动态代理类了而不是之前我们自己手动创建的类对象了。

 

二:JDK动态代理生成的代理类分析

在上文说到通过代理类 生成的类已经不是之前我们手动生成的类对象了。即样例中的instance已经为JDK动态代理新生成的一个代理类了。这里我们手动来生成一个接口的代理类,看看他的内部究竟是什么样的结构。

    public static void main(String[] args) throws IOException {
        //基于Person接口 生成一个代理类的类名为$Proxy0的类字节码文件
        byte[] generateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
        //输出为字节码文件
        FileOutputStream fos =new FileOutputStream("$Proxy0.class");
        fos.write(generateProxyClass);
        fos.close();
    }

通过以上代码生成的解码码class文件经过反编译为:

import com.sg.spring04.proxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

//代理类$Proxy0 继承与Proxy,以及实现了接口Person
public final class $Proxy0 extends Proxy  implements Person
{
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler)   throws { 
	super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject) throws 
  {
    try {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值