前言

前面我们简单介绍了代理模式的使用Android设计模式详解之代理模式,我们也明白了动态代理模式的重要性,那动态代理究竟是如何实现将方法交给InvocationHandler.invoke执行的呢?本文就从源码的角度一步步去探究这个问题;

源码分析

从前面一篇文章我们知道动态代理是通过调用 Proxy.newProxyInstance()方法来实现的,我们就从这个方法入手
Proxy.newProxyInstance()方法:

 //constructorParams成员变量private static final Class<?>[] constructorParams ={ InvocationHandler.class };public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{  //先检查传入的InvocationHandler是否为空,为空则直接抛空指针Objects.requireNonNull(h);//克隆一份代理接口,并通过传入的classLoader去获取一个代理classfinal Class<?>[] intfs = interfaces.clone();Class<?> cl = getProxyClass0(loader, intfs);try {//获取代理class的带有InvocationHandler参数的构造函数final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;//如果构造函数是私有的,反射设置可访问if (!Modifier.isPublic(cl.getModifiers())) {cons.setAccessible(true);  }//通过反射生成代理对象return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}

整体看下来还是比较轻松的,主要就是通过传入的类加载器代理接口以及InvocationHandler调用反射去创建一个代理类的对象实例;

这里我们再重点分析下代理类的创建流程, Class<?> cl = getProxyClass0(loader, intfs);这段代码

 //proxyClassCache缓存private static final WeakCache<ClassLoader, Class<?>[], Class<?>>proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}//很明显这里做了缓存处理return proxyClassCache.get(loader, interfaces);}

可以看到代理类最终是交给ProxyClassFactory工厂类创建的,我们就重点看下ProxyClassFactory

    /*** 一个工厂函数,在给定ClassLoader和接口数组的情况下生成、定义和返回代理类。*/private static final class ProxyClassFactoryimplements BiFunction<ClassLoader, Class<?>[], Class<?>>{// 代理类的后缀private static final String proxyClassNamePrefix = "$Proxy";// 用于生成唯一代理类名的下一个数字private static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);//遍历代理接口for (Class<?> intf : interfaces) {Class<?> interfaceClass = null;try {//反射获取代理接口对应的classinterfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {//通过classLoader加载的class与原代理接口不一致则抛异常throw new IllegalArgumentException(intf + " is not visible from class loader");}//反射获取代理接口对应的class不是一个接口则抛异常if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}//验证代理接口是否重复if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null;     //代理类包名int accessFlags = Modifier.PUBLIC | Modifier.FINAL;//遍历代理接口,获取包名信息for (Class<?> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags = Modifier.FINAL;String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) {proxyPkg = "";}{//获取接口中的所有方法List<Method> methods = getMethods(interfaces);//根据方法签名等信息进行排序Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);//如果方法中的任何两个方法具有相同的名称和参数,但返回类型不一致,则抛异常validateReturnTypes(methods);//获取所有的异常集合、方法集合List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);Method[] methodsArray = methods.toArray(new Method[methods.size()]);Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);//代理类名依次递增long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;//生成代码类return generateProxy(proxyName, interfaces, loader, methodsArray,exceptionsArray);}}}

代理类的创建工作交给ProxyClassFactory工厂来完成,ProxyClassFactory.apply方法会遍历所有的代理接口,并做校验、方法排序等工作,最终会调用generateProxy方法来生成代理类,而generateProxy方法是一个native方法!!!

    private static native Class<?> generateProxy(String name, Class<?>[] interfaces,ClassLoader loader, Method[] methods,Class<?>[][] exceptions);

经过上面的步骤,就通过调用 Proxy.newProxyInstance()方法生成了代理类,并创建了代理类的实例对象返回;

那这个创建的代理类长什么样呢?为什么通过代理类的对象调用代理接口方法就可以执行到InvocationHandler.invoke方法中呢?

我们在调用 Proxy.newProxyInstance()方法前,修改下系统属性如下:

 //修改属性设置保存生成的proxy文件System.getProperties().setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true")

这样我们就可以看到生成的代理对象

我这里还是前面的租客租房例子,生成的代理对象如下:

package com.sun.proxy;import com.crystal.essayjoker.pattern.proxy.dynamic.IRental;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements IRental {private static Method m1;private static Method m3;private static Method m4;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final void renting() throws  {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void rentingOut() throws  {try {super.h.invoke(this, m4, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("com.crystal.essayjoker.pattern.proxy.dynamic.IRental").getMethod("renting");m4 = Class.forName("com.crystal.essayjoker.pattern.proxy.dynamic.IRental").getMethod("rentingOut");m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

可以看到调用proxy的代理方法最终还是通过反射调用传入的InvocationHandler的invoke方法,至此谜题解开;

总结

动态代理的实现原理:
调用 Proxy.newProxyInstance()方法会通过反射带有InvocationHandler参数的构造函数生成代理类,并返回代理类的实例,当调用代理类的方法时,又会通过反射执行InvocationHandler对应的invoke方法,从而实现动态代理这套机制;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

Android动态代理源码分析相关推荐

  1. jdk动态代理源码分析(一)---代理的定义

    最近在看rpc的实现原理,发现大部分通用的rpc框架在实现远程调用的时候,都是通过java动态代理封装好了通信细节,让用户可以像调用本地服务一样调用远程服务.但是关于java动态代理有两个问题想不通: ...

  2. javabean反射改字段内容_BAT程序员编写:深入理解 Java 反射和动态代理源码分析...

    什么是反射 反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. 通过反射机制,可以在运行时访问 Java ...

  3. 动态代理源码分析,实现自己的动态代理

    什么是代理 增强一个对象的功能 买火车票,app就是一个代理,他代理了火车站,小区当中的代售窗口 java当中如何实现代理 java实现的代理的两种办法 代理的名词 代理对象 增强后的对象 目标对象 ...

  4. 动态代理及JDK动态代理源码分析

    1.为什么要动态代理 现在有这样一个需求:在聊天系统中,把每一个所说的话记录到日志文件里面,初学者可能是这样来设计 在speak方法中调用log方法,记录到数据库.这样设计有明显的不足:1.log方法 ...

  5. jkd动态代理源码分析

    代理对象的生成方法是: Proxy.newProxyInstance(...),进入这个方法内部,一步一步往下走会发现会调用 ProxyGenerator.generateProxyClass(),这 ...

  6. Java动态代理源码详解

    一.概述   前言:本文除了讲解JDK动态代理及CGLIB动态代理实例和应用外,还会讲解JDK动态代理源码实现过程以及自己写一手个JDK动态代理等.   动态代理在很多底层框架中都会用得到,比如在Sp ...

  7. JDK动态代理源码解析

    分析版本jdk1.8 在分析jdk动态代理之前,先来了解java WeakReference弱引用的使用.运行期创建目标对象的代理非常耗时,使用缓存来存储生成的代理类显得尤为重要.jdk动态代理使用弱 ...

  8. 深入剖析JDK动态代理源码实现

    动态代理.静态代理优缺点 优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性.这是代理的共有优点.动态代理只有在用到被代理对象的时候才会对被代理类进行类加载. 而静态代理在编译器就已经开始占内存 ...

  9. android 动画原理源码分析之Animation

    在开发移动应用程序的时候用到动画是家常便饭的事,但是你有没有想过它是怎么实现的呢?今天小弟就在此分析一下. 1 startAnimation 方法. 设置好animation变量,刷新父视图绘画缓存. ...

最新文章

  1. BCH比特币现金有何魅力,让“比特币耶稣”和矿工们都看涨买入?
  2. WIN 7下绑定网关MAC地址
  3. 完整的由客户端登录(注册)思路
  4. javaweb mysql 连接池 c3p0 配置_C3P0连接池详细配置与实现(2)全局使用
  5. linux下vi的一些简单的操作
  6. android 视频转字节,如何将视频文件(.mp4)格式转换为android中的二进制格式?...
  7. android jni framework,Android Framework层的JNI机制(二)
  8. PHP 正则表达式资料
  9. 罗永浩今晚带货iPhone 12:价格将有惊喜!
  10. 从零开始造一个“智障”聊天机器人
  11. 谷歌修复4个已遭利用的安卓 0day
  12. ...提升网站程序开发安全的6大诀窍...
  13. (亲测有效).net framework 在计算机上已安装了更高的 4.x 版本,则无法安装以前的 4.5 版本。
  14. 系统日志查看journalctl命令详解
  15. 在WinCC V7.3中如何导出过程值进行数据归档
  16. 怎么清楚计算机硬盘搜索记录,win7系统怎么清除搜索记录_windows7删除计算机搜索记录的方法...
  17. HTTP代理服务器的工作原理
  18. 链接下载(在线链接下载)
  19. Doc和Docx有什么区别
  20. 科达高密度服务器型号,科达2017存储新品首秀丨“三高一低”24盘位IPSAN磁盘存储阵列...

热门文章

  1. inventor2014 0x0000142错误 终极解决方案
  2. xlsx表格怎么做汇总统计_Excel表格中如何进行分类汇总计数和求和 值得收藏
  3. NFT数字藏品版权如何保护?
  4. AD18图纸信息(右下角)信息设置
  5. u-boot-2014.10移植第14天----在SDRAM中运行
  6. 2020面试准备(一)
  7. 抖音自媒体起号必看,如何找到对标账号?
  8. source insight添加astyle
  9. TextView 判断自动换行
  10. 微信小程序账号被冻结,如何找回