美文网首页Android 开发技术源码解析
Retrofit2 源码解析之动态代理

Retrofit2 源码解析之动态代理

作者: 1cf2c90a5564 | 来源:发表于2018-05-11 13:22 被阅读192次

    基于 Retrofit 2.3.0 & Android 8.1 分析 Java 动态代理在 Android 上的实现
    本文为博主原创文章,未经允许不得转载
    推荐阅读另一篇博文:《Handler 源码解析》

    动态代理最难理解的就是动在何处,其实动就动在代理类是完全在内存中生成的,包括创建类字节码、加载、链接、初始化代理类对象整个过程。不同于那些在编译期就生成 Xxx.class 的对象,那是磁盘文件,是人眼可见的,动态代理类的的字节码仅存在于内存中,是看不见的。本文主要介绍代理类的生成过程,看完本文应该可以彻底理解动态代理。

    Retrofit 使用示例

    public interface XinZhiWeatherApi {
        @GET("{type}?key=xxxxxxxxxx&&language=zh-Hans&unit=c")
        Flowable<WeatherBean> getNowWeather(@Path("type") String type, @Query("location") String location);
    }
    
    public static XinZhiWeatherApi initWeatherApi() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .retryOnConnectionFailure(true)
                .connectTimeout(10, TimeUnit.SECONDS)
                .build();
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(client)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit.create(XinZhiWeatherApi.class);
    }
    

    如上所示,Retrofit 的使用非常简单。本文只关注 retrofit.create()

    Retrofit.create

    Retrofit.java

      public <T> T create(final Class<T> service) {
        // 必须是接口类型且不能继承其它接口,否则抛出异常
        Utils.validateServiceInterface(service);
        // validateEagerly 默认是 false
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        // 返回动态生成的代理类
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    我们看到,Retrofit 的动态代理使用比较简单,不涉及接口的实现类,只有一个匿名的 InvocationHandler 类。下面写个示例代码(使用 IntelliJ IDEA 编写):

    public interface ISubject {
        void sayHello();
    }
    
    public static void main(String[] args) {
        ISubject subject = (ISubject) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{ISubject.class},
            new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("InvocationHandler$invoke: call " + method.getName());
                        return 0;
                    }
                });
    
        System.out.println("class of subject: " + subject.getClass().getName());
        System.out.println("super class of subject: " + subject.getClass().getSuperclass().getSimpleName());
        System.out.println("interface implemented by subject: " + Arrays.toString(subject.getClass().getInterfaces()));
        System.out.println("fields of subject: " + Arrays.toString(subject.getClass().getDeclaredFields()));
    
        subject.sayHello();
    }
    

    一个非常简单的动态代理使用代码,只声明了一个接口,并没有实现这个接口,同 Retrofit 一样。日志输出如下:

    class of subject: com.sun.proxy.$Proxy0
    super class of subject: Proxy
    interface implemented by subject: [interface com.yaren.proxy.ISubject]
    fields of subject: [private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m1, private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m3, private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m2, private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m0]
    InvocationHandler$invoke: call sayHello
    

    从输出结果可以看出,动态代理对象 subject 的类名是 $Proxy1、父类是 Proxy、实现的接口是 ISubject,并且调用 subject 的 sayHello() 时,匿名内部类 InvocationHandler 的 invoke() 方法得到了调用。看到这里,已经能够猜出该代理类的大概实现了:

    public class $Proxy1 extends Proxy implement ISubject {
        // sayHello() 对应的 Method 对象
        private static Method m1;
        
        @Override
        public void sayHello() {
            try {
                // h 为 Proxy 中 InvocationHandler 类型的成员变量
                super.h.invoke(this, m1, (Object[]) null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    下面通过 ProxyGenerator.generateProxyClass() 生成动态代理类的字节码数组,再转为 .class 文件,最后反编译生成 .java 文件,验证一下上面的猜测:

        // subject 为上面生成的动态代理对象
        String proxyName = subject.getClass().getName() + ".class";
        byte[] clazz = ProxyGenerator.generateProxyClass(proxyName, new Class[]{ISubject.class});
        try {
            OutputStream out = new FileOutputStream(proxyName);
            InputStream is = new ByteArrayInputStream(clazz);
            byte[] buff = new byte[1024];
            int len;
            while ((len = is.read(buff)) != -1) {
                out.write(buff, 0, len);
            }
            is.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    

    生成的文件为 com.sun.proxy.$Proxy0.class,反编译源码如下(为便于阅读,调整了变量和方法的顺序):

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.sun.proxy.$Proxy0;
    
    import com.yaren.proxy.ISubject;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class class extends Proxy implements ISubject {
        private static Method m0;
        private static Method m1;
        private static Method m2;
        private static Method m3;
    
        static {
            try {
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.yaren.proxy.ISubject").getMethod("sayHello");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    
        public class(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final int hashCode() throws  {
            try {
                return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
        
        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 void sayHello() throws  {
            try {
                super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
    }
    

    可以看到,除了 sayHello() 外,还重写了 equals()、hashCode()、toString()。以上是动态代理在 jdk 中的实现,因为 Android 中无法使用 sun.misc.ProxyGenerator 类,所以使用 java 环境来测试。接下来看动态代理在 Android 中的实现。

    Proxy.newProxyInstance

    Proxy.java

        // 动态代理类构造器的参数类型
        private static final Class<?>[] constructorParams = { InvocationHandler.class };
    
        // 在 newInstance() 中,会调用动态代理类的构造器传入 invocationHandler 对象
        protected Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
        }
    
        @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            // invocationHandler 不能为null
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            
            // 这句是关键:查找或生成代理类,cl 即为代理类的 Class 对象
            Class<?> cl = getProxyClass0(loader, intfs);
    
            
            try {
                // 调用动态代理类参数类型为 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);
            }
        }
    

    Proxy.getProxyClass0

    Proxy.java

        // 缓存查找动态代理类 Class 对象的工厂类 (即WeakCache$Factory)
        // WeakCache 有三个泛型,第一个为 Key,第二个为 SubKey, 第三个为 Value
        // 此处 Key 为 classloader,SubKey 为 KeyFactory( KeyFactory 用来根据被代理的接口生成 subKey),
        // Value 为 动态代理类的类类型
        // ProxyClassFactory 用于生产动态代理类的 Class 对象 
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
        private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
            // 接口数量不能超过 65535,此处为 1
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
            // 如果由 loader 加载的实现 interfaces 的动态代理类的 Class 对象已经存在,直接返回已加载的 Class 对象,
            // 否则调用 ProxyClassFactory 创建新的 Class 对象
            return proxyClassCache.get(loader, interfaces);
        }
    

    WeakCache.get

    WeakCache.java

        // 为便于阅读,已将方法中所有泛型替换为具体类型
        public Class<?> get(ClassLoader key, Class<?>[] parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
    
            Object cacheKey = CacheKey.valueOf(key, refQueue);
    
            ConcurrentMap<Object, Supplier<Class<?>>> valuesMap = map.get(cacheKey);
            // step1. 初次调用,valuesMap 肯定为 null
            if (valuesMap == null) {
                // step2. 新建一个 Map 对象
                ConcurrentMap<Object, Supplier<Class<?>>> oldValuesMap
                    = map.putIfAbsent(cacheKey,
                                      valuesMap = new ConcurrentHashMap<>());
                if (oldValuesMap != null) {
                    valuesMap = oldValuesMap;
                }
            }
            
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            // valuesMap 是刚 new 的,所以 supplier 肯定是 null
            Supplier<Class<?>> supplier = valuesMap.get(subKey);
            // Factory 是 Supplier 的实现类,调用其 get() 时,会内部调用 ProxyClassFactory.apply()
            // 获得代理类的 Class 对象
            Factory factory = null;
    
            while (true) {
                // step5. 第二次循环时,supplier 不为 null
                if (supplier != null) {
                    // step6. 调用实现类 factory 的 get(), 返回代理类的 Class 对象
                    Class<?> value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }
    
                if (factory == null) {
                    // step3. 新建 Factory 对象 
                    factory = new Factory(key, parameter, subKey, valuesMap);
                }
    
                if (supplier == null) {
                    // step4. 将 factory 关联至 subkey 并赋给 supplier
                    supplier = valuesMap.putIfAbsent(subKey, factory);
                    if (supplier == null) {
                        supplier = factory;
                    }
                } else {
                    if (valuesMap.replace(subKey, supplier, factory)) {
                        supplier = factory;
                    } else {
                        supplier = valuesMap.get(subKey);
                    }
                }
            }
        }
    

    Factory.get

    WeakCache$Factory.java

            // 为便于阅读,已将方法中所有泛型替换为具体类型
            @Override
            public synchronized Class<?> get() {
                Supplier<Class<?>> supplier = valuesMap.get(subKey);
                // 此处为 ==
                if (supplier != this) {
                    return null;
                }
    
                Class<?> value = null;
                try {
                    // 调用 valueFactory.apply(key, parameter) 生成并返回代理类的 Class 对象
                    // valueFactory 在 WeakCache 的构造器中传入,通过上面分析可知,其类型为 ProxyClassFactory
                    value = Objects.requireNonNull(valueFactory.apply(key, parameter));
                } finally {
                    if (value == null) {
                        valuesMap.remove(subKey, this);
                    }
                }
                assert value != null;
    
                CacheValue<Class<?>> cacheValue = new CacheValue<>(value);
    
                if (valuesMap.replace(subKey, this, cacheValue)) {
                    reverseMap.put(cacheValue, Boolean.TRUE);
                } else {
                    throw new AssertionError("Should not reach here");
                }
    
                return value;
            }
    

    ProxyClassFactory.apply

    Proxy$ProxyClassFactory.java

            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                // interfaces 即为代理类要实现的接口,此处仅有一个接口需要实现
                // IdentityHashMap 使用 == 比较 key,该 Map 很少使用
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    // 类类型不等,抛出异常
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                    //  不是接口类型,抛出异常
                    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;
    
                // 记录所有非 public 接口的包名,以便代理类可以定义在相同目录下。
                // 校验所有非 public 接口是否在同一个目录下,不是则抛出异常。
                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");
                        }
                    }
                }
    
                // 我们接口是 public 的,所以包名为 ""
                if (proxyPkg == null) {
                    proxyPkg = "";
                }
    
                {
                    // Android 平台直接调用 native 代码生成代理类 Class 对象,而不是像 jdk 一样,通过 ProxyGenerator 类。
                    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()][]);
    
                    // 生成代理类的名称,此处为 "$Proxy1"
                    long num = nextUniqueNumber.getAndIncrement();
                    String proxyName = proxyPkg + proxyClassNamePrefix + num;
                    // 调用 native 代码生成代理类 Class 对象
                    return generateProxy(proxyName, interfaces, loader, methodsArray,
                                         exceptionsArray);
                }
            }
    

    结语

    看完本文,应该对 Retrofit 所使用的动态代理技术有了更深入的理解。代理类已经生成,接下来每个接口方法的调用都会委托给
    InvocationHandler 处理,只要在 invoke() 中解析下 method 对象的注解参数,然后把活交给 okhttp、gson 就行了。至于 jvm 如何加载、链接、初始化代理类,则不在本文讨论范围。感兴趣的可以阅读《深入Java虚拟机_JVM高级特性与实践》第七章,里面会有详细介绍。

    相关文章

      网友评论

      • 193a9bef86ef:有点晦涩难懂,不过楼主写的很好了,感谢楼楼分享!
      • 业松:动态代理真tm难,收藏了
        1cf2c90a5564:@业松 看完包会!😏

      本文标题:Retrofit2 源码解析之动态代理

      本文链接:https://www.haomeiwen.com/subject/oyjfdftx.html