Retrofit2 源碼解析之動態代理

基於 Retrofit 2.3.0 & Android 8.1 分析 Java 動態代理在 Android 上的實現
未經容許不得轉載

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()java

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 編寫):git

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 同樣。日誌輸出以下:github

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,反編譯源碼以下(爲便於閱讀,調整了變量和方法的順序):app

//
// 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 中的實現。jvm

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");
        }

        // 若是由該 classloader 加載的實現給定 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 所使用的動態代理技術有了更深刻的理解。至於 jvm 如何加載、連接、初始化代理類,則不在本文討論範圍。感興趣的能夠閱讀《深刻Java虛擬機_JVM高級特性與實踐》第七章,裏面會有詳細介紹。ide

相關文章
相關標籤/搜索