前两天刚刚把Retrofit的源码看完,发现对于底层的请求调用还是通过okhttp来进行的.
现在来研究一下okhttp的源码.
由于okhttp比retrofit细节,结构上要更复杂.预期以3个篇幅来进行讲解.
分别是:
上篇:okhttpclient的参数,调用.
中篇:getResponseWithInterceptorChain
下篇:各个Interceptor的作用和自定义Interceptor
画个重点.
我们看完Retrofit后知道它的核心代码是 Proxy.newProxyInstance()
那么OkHttp的重点是什么呢?
getResponseWithInterceptorChain()
本次源码解读将基于OkHttp最新版本3.13.1进行.
我将以看过okhttp源码后的视角来写这篇流水账博客.
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.github.com/")
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println("请求成功");
}
});
最常见的用法,我们先创建了一个OkHttpClient,然后通过Builder模式创建了一个Request,再将Request传到newCall()内,调用enqueue()/execute()即可.
这段基础调用代码,我们主要学习一下3个内容.
这个主要的类,我们看一下全局的变量,几十个呢.
挑几个重点看一下吧.
反正看得懂就看,看不懂就关掉,千万别一棵树吊死了.(完全看不懂的,我就不写出来了,23333)
Dispatcher dispatcher
这玩意主要功能就字面意思…是一个调度器.
Flux的diapatcher负责全局调度传递Action.那我们看看okhttp的.
最大请求数量64、同一个Host最大请求数量5、idleCallback(闲置的callback)、executorService(线程池)、3个queue(分别是准备好的异步queue,正在运行的异步queue,正在运行的同步queue).
okhttp内,dispather的作用是调度传递各种call,如RealCall/AsynCall.
具体的作用等待看一下后续的,再思考具体的作用.
List protocols
点进去看一下这个Protocol,
emmm…
HTTP_1_0、HTTP_1_1、SPDY_3、HTTP2、H2_PRIOR_KNOWLEDGE、QUIC
下面还有一个get方法,传入对应的String protocol,给你匹配对应的Hypertext Transfer Protocol (超文本协议).
我知道的也就http1.0、http1.1、spdy、http2.0了,其他的是什么鬼.
反正知道了大概这就是okhttp支持的协议了.(我们常用的也就是http1.1罢了)
List connectionSpecs
点进去看一下ConnectionSpec,
CipherSuite !!!
TLS打头的…
这妥妥的就是HTTPS连接建立,TLS安全层 客户端和服务端Client Hello/Service Hello 使用的非对称加密/对称加密/HASH算法的 支持合辑了.
List interceptors/List networkInterceptors
这2个Interceptor涉及到okhttp的最核心的东西getResponseWithInterceptorChain,后面再分析.
CookieJar cookieJar
CookieJar这个东西,我还是认为有必要提一句的.
核心的就这2个方法了,
当初最开始使用这个的时候,我也纠结过这是啥玩意.
其实是很简单
完全可以自己实现一下CookieJar,然后自己弄一个Map存储一下.
CookieJar I_NEED_COOKIES = new CookieJar() {
Map> mCookie = new HashMap();
@Override
public void saveFromResponse(HttpUrl url, List cookies) {
mCookie.put(url.toString(), cookies);
}
@Override
public List loadForRequest(HttpUrl url) {
return mCookie.get(url.toString());
}
};
和Retrofit的ServiceMethodCache,loader.ProxyCache一样,有就直接拿,没有就存进去.
OkHttpClient newOkHttpClient = new OkHttpClient.Builder()
.certificatePinner(
new CertificatePinner.Builder().add("指定的host","证书公钥(sha256/XXXX)").build())
.build();
对了,如果不记得证书公钥,可以直接随便写一个,log有返回正确的哟…
点进去看看,复读机
emmm…
RealCall.newRealCall(this, request, false /* for web socket */);
一个参数变3个参数,一个okhttpclient,一个传入的request,一个websocket.
临时插播一下webSocket的信息.
据我所知,webSocket的使用场景是那种需要 长连接,服务器频繁刷新数据的场景.比如说 金融?
听朋友说,智能家居方面也用这玩意了,最近面试问的还挺多?
完全没用过啊,开坑学习,研究预定!!!
再看看newRealCall().其实就是创建了一个RealCall.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
OK,期待一下enqueue/execute在这个RealCall里面的调用吧.
终于到了关键的请求部分了.
让我们点进去看看 复读机.png
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
关键的代码就2行…
调用dispatcher的executed()方法,将这个包装着request的RealCall放到了runningSyncCalls这个queue里面去了.
然后就直接通过getResponseWithInterceptorChain()获取到了response…
这就结束了, 就是辣么简单.
有的人可能就要说了.不对啊,不是说okhttp请求是自己实现的socket连接么,
哪里连接了socket?又在哪里接受到了数据呢?咋就直接返回了?
client.dispatcher().enqueue(new AsyncCall(responseCallback));
先看看这个dispatcher.enqueue做了什么.
1.先将这个包装着request的RealCall放到了readyAsyncCalls这个euque里面去了.
2.调用promoteAndExecute();
3.检查当前请求数量和同一Host下请求数量,将readyAsyncCalls的call放到runningAsyncCalls内.
4.使用一个叫做AsyncCall调用executeOn()
再看看enqueue传入的参数,刚好也是一个AsyncCall,巧了.
在这个AsyncCall内调用executeOn,也就是启用线程池来调用这个AsyncCall.
AsyncCall继承了NamedRunnable.看一眼这个runnbale的run(),然来调用的是execute();
execute()也通过getResponseWithInterceptorChain()拿到了response.
最后将response,通过在MainActivity里面创建的CallBack回调至Activity内.
okhttp的整体调用(enqueue/execute)逻辑,基本就是这样了.
发现最核心的HTTP请求处理部分都在getResponseWithInterceptorChain()里面了.
下一篇将开始讲解这个核心.