注:以下內(nèi)容為本人自己做(chao)的學(xué)習(xí)筆記,可能含有少兒不宜的誤導(dǎo)性內(nèi)容,學(xué)習(xí)Retrofit請看參考文章。。。
參考文章:http://www.itdecent.cn/p/0d919e54eef0
OkHttp使用:
//創(chuàng)建client對象
OkHttpClient client = new OkHttpClient();
//創(chuàng)建Request
Request request = new Request.Builder()
.url(url)
.build();
//執(zhí)行請求,獲取結(jié)果
client.newCall(request).enqueue(new Callback() {
@override
public void onFailure(Call call, IOException e) {
}
@override
public void onResponse(Call call, Response response) throws IOException {
content.setText(response.body().string());
}
});
以上既是OkHttp的使用方法,使用OkHttp時需要自己處理多線程,開啟子線程發(fā)送請求,收到數(shù)據(jù)后需要使用Handler來更新UI。
放屁,OkHttp支持同步和異步兩種方式發(fā)送請求,execute及enqueue。
Retrofit使用:
//定義API接口
public interface APIService {
@GET("/test.json")
Call<Model> getResult();
@GET("/search.json")
Call<SearchResult> getResult();
}
//創(chuàng)建Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();
//獲取接口Service的代理對象
APIService apiService = retrofit.create(APIService.class);
//調(diào)用代理對象的方法獲取到Call對象(Call對象是對Request的一層封裝)
Call<Model> result = apiService.getResult();
//異步執(zhí)行請求
result.enqueue(new Callback<Model>() {
@override
public void onResponse(Response<Model> response, Retrofit retrofit) {
content.setText(response.body().toString());
}
@override
public void onFailure(Throwable t) {
content.setText("error");
}
});
單從代碼量來看,Retrofit并不比OkHttp需要寫的代碼少。之所以要對OkHttp做這樣的封裝,我覺得原因在于:
1.不需要知道什么是Request,什么是Client以及Call對象,閉著眼用就行。
2.把網(wǎng)絡(luò)接口統(tǒng)一封裝到一個接口類中,看上去更規(guī)整。
3.使用Annotation標(biāo)識請求類型和路徑,雖然我并不知道這么干有什么卵用,大家都說好才是真的好。
既然要分享框架,那就必須得看源碼。
創(chuàng)建API接口類和用Builder創(chuàng)建Retrofit不提也罷。直接看重點(diǎn):
APIService apiService = retrofit.create(APIService.class);
傳一個接口類進(jìn)去,返回一個實(shí)例給我。
厲害了。
其實(shí)也并沒那么神奇,我猜測這個方法是這樣的:傳一個接口進(jìn)去,里面用代碼創(chuàng)建一個類,實(shí)現(xiàn)我傳進(jìn)去的這個接口,把那個類的實(shí)例返回給我。
咦?用代碼創(chuàng)建類?對我這種白菜來說也是很新鮮的,用代碼寫代碼看上去也是屌屌的。
嘍一眼源碼
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
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, 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);
}
});
}
關(guān)鍵當(dāng)然是在return那一句。咦,Proxy是個啥...
Java動態(tài)代理
先說說我是怎么理解代理的。作為年輕程序猿,大都非常老實(shí)本分加勤奮,不愿意卷入世俗紛爭,假裝與Boss談笑風(fēng)生。所以這個時候,就要給每一個程序猿配送一個解說員,由解說員去解決談笑風(fēng)生的事,程序猿專心寫好程序就行了。這個解說員就可以看做是一個代理,事實(shí)上,這個代理的目的就是把程序猿和Boss進(jìn)行解耦,讓Boss專心談笑風(fēng)生,程序猿專心寫程序。
然而事與愿違,小公司請不起那么多人當(dāng)解說員,所以就有了動態(tài)代理,也就是Leader。Leader在不出事兒的時候(編譯時)是喝茶的,一旦一個團(tuán)隊的某個程序猿出了問題(運(yùn)行時),Leader就會跳出來變身成該程序猿的解說員去與Boss談笑風(fēng)生。
扯完了蛋,來看看動態(tài)代理的代碼:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//權(quán)限判斷等,忽略
//生成代理類
Class<?> cl = getProxyClass0(loader, intfs);
//調(diào)用構(gòu)造器,生成實(shí)例
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
//各種異常處理
}
}
看方法名就能看出來,此方法是用來new代理實(shí)例的。
有三個參數(shù):
1.ClassLoader,類加載器,用來加載這個類...算了其實(shí)我不懂,反正就是要這個參數(shù)拿去創(chuàng)建類的。
2.Class<?>[] interfaces,要繼承的接口數(shù)組,這個我懂。
3.InvocationHandler,祈禱處理器......這個是代理類要完成的任務(wù)的具體實(shí)現(xiàn)。
Class<?> cl = getProxyClass0(loader, intfs);
這行代碼創(chuàng)建了一個代理類,實(shí)現(xiàn)了傳進(jìn)去的接口。
return cons.newInstance(new Object[]{h});
這行代碼返回上面創(chuàng)建的Class的新的實(shí)例,順便把接收到的InvocationHandler傳了進(jìn)去。
跟Retrofit結(jié)合來看一下。還記得這句代碼吧:
RestApi restApi = retrofit.create(RestApi.class);
我們傳一個接口類進(jìn)去,再看一遍Retrofit的create:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
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, 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);
}
});
}
它拿到了我們傳進(jìn)去的接口類的ClassLoader作為創(chuàng)建動態(tài)代理方法的第一個參數(shù),新建一個Class數(shù)組承載我們傳進(jìn)去的接口,最后它自己寫了一個InvocationHandler傳進(jìn)去。
最終,動態(tài)代理的newProxyInstance返回一個包含InvocationHandler,實(shí)現(xiàn)了Retrofit傳進(jìn)去接口的APIService接口類的代理類實(shí)例給Retrofit(自己看著都累)。Retrofit再把這個代理類實(shí)例返給我們。
OK,上面回顧的是傳入一個接口類給Retrofit,Retrofit返回代理實(shí)例給我們的實(shí)現(xiàn)流程。這時候還剩一個磨人的小妖精,就是那個InvocationHandler究竟是干啥的。
要探究這個問題就得看看生成的動態(tài)代理類里面是什么樣子的了。
Class<?> cl = getProxyClass0(loader, intfs);
這句代碼就是用來生成代理類的,那么來看看getProxyClass這個方法里頭干了啥。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
//一個代理類最多能夠?qū)崿F(xiàn)65535個接口
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 這里Proxy做了一次緩存,如果之前生成過這個Classloader和interfaces的代理類,那么這里直接返回
//否則新生成類的字節(jié)碼文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//將字節(jié)碼加載到JVM
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
retrun proxyClass;
}
可以看到,最終是調(diào)用ProxyGenerator的generateProxyClass方法生成類的字節(jié)碼并加載到JVM,再返回。
至于這個方法是怎么生成的,咱就不追下去了(因?yàn)閰⒖嫉奈恼吕餂]追...)。不過可以通過它生成的代理類反推它干了什么。
把生成的代理類的Class文件導(dǎo)出并反編譯,可以看到,這個代理類繼承自Proxy,實(shí)現(xiàn)了傳進(jìn)去的所有接口。它除了實(shí)現(xiàn)了Object基礎(chǔ)的equals,toString和hashCode這幾個方法外,還實(shí)現(xiàn)了我們接口定義的方法。
//以下代碼純手打,不一定準(zhǔn)確
public final Call<Model> getResult() throws {
try {
return (Call)super.h.invoke(this, m3, new Object[]{"retrofit"});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
其中,m3是通過反射拿到的Method對象。
private static Method m3;
m3 = Class.forName("proxy.GenerateClass$APIService").getMethod("getResult", new Class[] {});
我們拿到接口的動態(tài)代理實(shí)例后,直接調(diào)用動態(tài)代理中實(shí)現(xiàn)的我們的接口定義的getResult方法,此方法會把調(diào)用轉(zhuǎn)發(fā)給父類(Proxy)的InvocationHandler的invoke方法。
Call<Model> result = apiService.getResult();
此時Retrofit的create方法中的InvocationHandler的invoke回調(diào)被調(diào)用。
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// 如果method是Object的基礎(chǔ)方法,就正常執(zhí)行方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//據(jù)說是Java8兼容,忽略
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);
}
}
現(xiàn)在來看invoke回調(diào)。重點(diǎn)在最后三行代碼。
進(jìn)到ServiceMethod類中,看見注釋:
/** Adapts an invocation of an interface method into an HTTP call. */
翻譯一下就是說:把一個接口方法的invocation翻譯(適配)成一個HTTP 請求??梢灾苯永斫鉃椋篠erviceMethod把我們定義在APIService接口類中的方法翻譯成一個HTTP請求。具體就是翻譯接口類方法的注釋、參數(shù),然后自動加上什么Header啦,body啦的什么鬼。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
從這個方法可以看出來,每一個method對應(yīng)一個serviceMethod。
所以第一行代碼就是獲取到當(dāng)前method對應(yīng)的serviceMethod。
第二行代碼
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
這里是Retrofit封裝Call對象的OkHttpCall類。它的構(gòu)造函數(shù)可以接受一個serviceMethod和參數(shù)。
第三行代碼
return serviceMethod.callAdapter.adapt(okHttpCall);
不用說,肯定是把okHttpCall變成Call對象返回給我們。這里Retrofit留了拓展可能性。這里的callAdapter由CallAdapter.Factory生產(chǎn),默認(rèn)使用的是DefaultCallAdapterFactory。我們可以對其進(jìn)行定制,自定義一個CallAdapter.Factory的子類,然后返回其他的類型。
到現(xiàn)在為止,終于把Retrofit的create方法走完了。再看一遍這個方法回憶一下整個流程吧。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
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, 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);
}
});
}
其實(shí)也沒那么復(fù)雜...
再往回套一層,回到使用上面來,咱們已經(jīng)調(diào)用了動態(tài)代理實(shí)例的方法,拿到了Call對象。往下就是enqueue執(zhí)行了,這個是OkHttp的東西,在這里就不深究了。