大家好,我是Nixo,一枚剛畢業(yè)的Android小生贵试,這是我開坑源碼系列的第一篇文章,可能我的文章跟其他人不同攀操,我的文章并不像別人那樣的細枝末節(jié)所以我將本系列的文章稱為"簡要解析"主要是讓大家明白整個框架它的實現(xiàn)流程院仿,用了什么樣的技術(shù)去實現(xiàn)什么功能之所以用Retrofit作為我的第一個閱讀的框架是因為他的設(shè)計模式用的如火純情,非常值得我們學(xué)習(xí)速和。
因為本人技術(shù)有限歹垫,如果有不好的地方或者錯誤的地方希望大家指正。
Retrofit源碼簡要解析系列共有3篇文章加上番外篇2篇總共5篇 :
Retrofit源碼簡要解析(一)Retrofit是怎樣將接口轉(zhuǎn)變?yōu)轭悂硎褂玫?動態(tài)代理)
Retrofit源碼簡要解析(二)Retrofit是怎樣將接口抽象方法轉(zhuǎn)變?yōu)檎埱篌w的(注解處理器)
Retrofit源碼簡要解析(三)Retrofit是怎樣將返回體轉(zhuǎn)變?yōu)閷嶓w類的(反射颠放、CallAdapted排惨、CallAdapterFactory)
Retrofit源碼簡要解析番外(一)CallAdapterFactory對RxJava的支持
Retrofit源碼簡要解析番外(二)CallAdapterFactory對Kotlin協(xié)程的支持
今天我們來講一下Retrofit是怎么將接口轉(zhuǎn)為類來供我們使用的,其實這里說的不夠準(zhǔn)確碰凶,因為這個類已經(jīng)不是我們聲明的接口類了暮芭,可能我這么一說接口和類大家可能一時反應(yīng)不過來我貼一個代碼大家就會恍然大悟,原來你指的是這個欲低!
//GitHubApi.class 就是我所述的接口辕宏,里面定義了Retrofit的網(wǎng)絡(luò)請求抽象方法
//GitHubApi就是我所述的生成類
GitHubApi gitHubApi = retrofit.create(GitHubApi.class);
Call<List<GitHubApi.Contributors>> contributors =
gitHubApi.contributors("square", "retrofit",new Date());
如上代碼Retrofit是怎么一番操作將我們的接口變?yōu)榫唧w的類呢?這里用到了Java的動態(tài)代理(Proxy)砾莱,帶著這個懸念我們點開create的方法瑞筐,走進Retrofit類當(dāng)中,點開源碼發(fā)現(xiàn)我們來到了Retrofit.java的第130行代碼如下:
public <T> T create(final Class<T> service) {
//做一些安全判斷腊瑟,判斷是否為接口聚假,不是接口java原生的動態(tài)代理會報錯
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//create其實就是通過Java的動態(tài)代理將接口中定義的方法轉(zhuǎn)給了InvocationHandler的invoke方法
//在通過loadServiceMethod調(diào)用invoke,來發(fā)起網(wǎng)絡(luò)請求(下篇文章會講)
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }
, new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
//如果該方法是Object自帶的方法闰非,那么我們直接反射出來這些方法就可以了
//比如說是.equest() 膘格、 toString()
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// .isDefaultMethod是Java8的特性
//它的意思是接口中定義的方法,因為java8支持了接口定義默認方法(default)這一特性
//也就是說河胎,這里的if是判斷上述特性闯袒,如果是就直接調(diào)用
//如果不是,就使用loadServiceMethod來獲取方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//返回了 封裝了請求參數(shù)的一個接口游岳,它知道怎么發(fā)起網(wǎng)絡(luò)請求
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
我們可以看到政敢,這里使用了Proxy.newProxyInstance 典型的動態(tài)代理,今天解析的重點就是這里胚迫,我們點開newProxyInstance 看看它到底是怎么將接口進行代理喷户,生成接口的代理類吧,點開后我們來到Proxy.java的719行
//newProxyInstance傳入了ClassLoader 還有接口访锻,我們可以想象得到
//他是通過ClassLoader來生成代理類的褪尝。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
...
/*
* Look up or generate the designated proxy class.
具體實現(xiàn)類代理的方法 getProxyClass0
*/
Class<?> cl = getProxyClass0(loader, intfs);
return cons.newInstance(new Object[]{h});
...
}
然后我們點開getProxyClass0來進一步探尋真正實現(xiàn)了代理的方法闹获,點開后來到了Proxy的410行,我們看到了如下的代碼:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
在這里河哑,我們可以看到getProxyClass0返回了ProxyClassCache.get 避诽,我們思考一下,也就是說我們的Class是從proxyClassCache里獲取到的璃谨,距離真相并不遙遠沙庐,我們繼續(xù)往下點開ProxyClassCache我們可以看到proxyClassCache其實是一個 WeakCache,而WeakCache其實是ConcurrentMap佳吞,這里就不過多說明了拱雏,我們點開proxyClassCache后來到Proxy的239行
//注意我們這里的第二個參數(shù)ProxyClassFactory
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
是的,這個ProxyClassFactory就是我們的代理類的創(chuàng)造類了底扳,距離真想只有一步之遙铸抑,我們繼續(xù)點進ProxyClassFactory 為了大家方便理解,我這里將一些異常處理等非關(guān)鍵代碼進行了簡化處理衷模,大家可以對照源碼找到相應(yīng)的代碼來加深大家的理解鹊汛。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
//生成的代理類的名字$proxy
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
//這里我也沒看懂,應(yīng)該是生成的第幾個代理類
//這樣算芯,我們生成的代理類名字就是com.sun.proxy.$proxy0
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null柒昏;
//這里將我們的類名設(shè)置上去
interfaceClass = Class.forName(intf.getName(), false, loader);
}
//初始化包名
String proxyPkg = null; // package to define proxy class in
//設(shè)置類的Modifier 我們的代理類為public final的類型
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
//將方法設(shè)置為final的靜態(tài)方法
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");
}
}
}
//設(shè)置代理類名 也就是com.sun.proxy.$proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
構(gòu)建我們的代理類熙揍,這里返回byte數(shù)組也就是字節(jié)碼
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
//通過defineClass0使用我們的classLoader將數(shù)組構(gòu)建成真正的class
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
以上就是Retrofit的接口代理類實現(xiàn)的簡要流程了职祷,大家是不是還有些略有發(fā)懵?不要緊届囚,我們可以自己實現(xiàn)ProxyGenerator.generateProxyClass方法有梆,生成byte[]然后通過IO流寫出一個class文件,你會發(fā)現(xiàn)這正是我們接口的代理類意系,來加深我們對java動態(tài)代理的理解泥耀,最后return的defineClass0便是我們一開始構(gòu)造出的GitHub.class啦,本文只是簡要的概述了動態(tài)代理的流程蛔添,Retrofit當(dāng)然還做了很多東西痰催,本文并沒有講到,這個并不是作為簡要解析的重點迎瞧,重點是讓大家用短暫的時間理解著去看懂整個流程夸溶,而非細枝末節(jié)。
最后感謝您看完本篇文章凶硅。