JDK动态代理原理分析

上篇文章写JDK动态代理实现的方式,其中涉及到一个重要的接口InvocationHandler和一种重要的类Proxy。JDK动态代理实现的原理是在根据被代理对象的接口,一个类加载器和InvocationHandler对象,动态生成一个代理类。这个类到底是什么样的呢?

	public static void main(String[] args) throws IOException {
                //将JDK生成的代理类保存到本地
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
		int array[] = {10, 8, 12, 31, 5, 1, 7, 8, 30, 10, 15};
		Sort sort  = new QuickSort();
		MyInvocationHandler myInvocationHandler = new MyInvocationHandler(sort);
		Sort sortProxy = (Sort)Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), sort.getClass().getInterfaces(), myInvocationHandler);
		sortProxy.sort(array);
	}

在代码前加上这行代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以将JVM动态生成的代理类保存在本地,在com/sun/proxy目录下面我们可以找到生成的代理类$Proxy0.class。我可以同时使用JD(java 反编译软件)将该代理给进行反编译。反编译的代码如下:

public final class $Proxy0 extends Proxy implements Sort
{
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void sort(int[] paramArrayOfInt)
  {
    try
    {
           //调用的是InvocationHandler实例的Invoke方法,在该方法中进行通过反射机制,调用了目标对象的sort方法。
      this.h.invoke(this, m3, new Object[] { paramArrayOfInt });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
            //静态初始化,初始接口中m1,m2,m3,m0属性,
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("test.Sort").getMethod("sort", new Class[] { Class.forName("[I") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

根据源码可知,代理类继承了Proxy实现了和目标对象类相同的接口(Sort),并且在静态初始化时将Sort接口中的方法(sort)通过Method类型成员变量m3保存。

动态代理代码执行的流程:

  1. 调用代理的的方法。(因为代理类实现了和目标对象的类相同的接口,所以对于用户来说就像是调用目标类方法一样
  2. 代理类中的方法调用InvocationHandler的invoke方法。
  3. 执行用户的增强逻辑(可有可无)。
  4. 通过反射调用目标对象的目标方法(调用时传入目标方法)。
  5. 执行用户增强逻辑(可有可无)。
  6. 返回调用结果。

注意:利用JDK实现动态代理时,被代理的对象必须实现了接口,如果没有实现接口是无法生成代理类的,并且接口数量不能超过65535. 

扩展:Spring框架在实现AOP是同时支持JDK动态代理技术和CGLIB的方式。

这两种方式实现动态代理是有所区别的,CGLIB是一种代码生成技术,实现动态代理时不要求目标对象的类不一定要实现接口的,因为CGLIB是同过直接继承目标对象的类并重写方法实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值