基於 Retrofit 2.3.0 & Android 8.1 分析 Java 動態代理在 Android 上的實現
未經容許不得轉載
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.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.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.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.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); } } } }
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; }
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