OKhttp源码解析详解系列
1 述 流程
- Okhttp的整个请求与响应的流程就是Dispatcher不断从Request Queue里取出请求(Call),根据是否已经存存缓存,从内存缓存或者服务器获取请求的数据。
- 请求分为同步和异步两种,同步请求通过调用Call.exectute()方法直接返回当前请求的Response,异步请求调用Call.enqueue()方法将请求(AsyncCall)添加到请求队列中去,并通过回调(Callback)获取服务器返回的结果。
- 流程图,很像计算机网络的OSI七层模型,Okhttp正式采用这种思路,利用拦截器Interceptor将整套框架纵向分层,简化了设计逻辑,提升了框架扩展性。
通过上面的流程图,我们可以知道在整个请求与响应流程中,以下几点是我们需要重点关注的:- Dispatcher是如何进行请求调度的?
- 各个拦截器是如何实现的?
- 连接与连接池是如何建立和维护的?
具体的函数调用链
2 请求的封装
请求是由Okhttp发出,真正的请求都被封装了在了接口Call的实现类RealCall中
2.1 Call接口如下所示:
public interface Call extends Cloneable {
//返回当前请求
Request request();
//同步请求方法,此方法会阻塞当前线程知道请求结果放回
Response execute() throws IOException;
//异步请求方法,此方法会将请求添加到队列中,然后等待请求返回
void enqueue(Callback responseCallback);
//取消请求
void cancel();
//请求是否在执行,当execute()或者enqueue(Callback responseCallback)执行后该方法返回true
boolean isExecuted();
//请求是否被取消
boolean isCanceled();
//创建一个新的一模一样的请求
Call clone();
interface Factory {
Call newCall(Request request);
}
}
2.2 RealCall的构造方法如下所示:
final class RealCall implements Call {
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//我们构建的OkHttpClient,用来传递参数
this.client = client;
this.originalRequest = originalRequest;
//是不是WebSocket请求,WebSocket是用来建立长连接的,后面我们会说。
this.forWebSocket = forWebSocket;
//构建RetryAndFollowUpInterceptor拦截器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
}
RealCall实现了Call接口,它封装了请求的调用,这个构造函数的逻辑也很简单:赋值外部传入的OkHttpClient、Request与forWebSocket,并 创建了重试与重定向拦截器RetryAndFollowUpInterceptor。
3 请求的发送
RealCall将请求分为两种
- 同步请求
- 异步请求
3.1 对比
同步请求
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
异步请求
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
AsyncCall --RealCall的内部类
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override
protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
从上面实现可以看出
相同点
- 不管是同步请求还是异步请求都是Dispatcher在处理:
- 在执行请求之前都会回调eventListener.callStart(this);
- 通过getResponseWithInterceptorChain()获取Response
不同点
- 同步请求:直接执行,并返回请求结果
- 异步请求:构造一个AsyncCall,并将自己加入处理队列中
- 异步请求多了responseCallback
3 请求的调度
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** Ready async calls in the order they'll be run. */
private final Deque readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque runningSyncCalls = new ArrayDeque<>();
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
synchronized void enqueue(AsyncCall call) {
//正在运行的异步请求不得超过64,同一个host下的异步请求不得超过5个
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
}
Dispatcher是一个任务调度器,它内部维护了三个双端队列:
- readyAsyncCalls:准备运行的异步请求
- runningAsyncCalls:正在运行的异步请求
- runningSyncCalls:正在运行的同步请求
- 同步请求就直接把请求添加到正在运行的同步请求队列runningSyncCalls中,
- 异步请求会做个判断:
如果正在运行的异步请求不超过64,而且同一个host下的异步请求不得超过5个则将请求添加到正在运行的同步请求队列中runningAsyncCalls并开始 执行请求,否则就添加到readyAsyncCalls继续等待。
4 请求的处理
4.1 getResponseWithInterceptorChain
final class RealCall implements Call {
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
}
短短几行代码,完成了对请求的所有处理过程。
- 首先一次将
用户添加的拦截器client.interceptors()--retryAndFollowUpInterceptor(重定向)--BridgeInterceptor--CacheInterceptor--ConnectInterceptor--networkInterceptors(非forWebSocket)--CallServerInterceptor加入到列表中。- 接着构造一个拦截器链index=0的链元素RealInterceptorChain
- 最终调用第一个链元素的proceed
4.2
public final class RealInterceptorChain implements Interceptor.Chain {
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//index的初始值是0
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
//获取链中的下一个拦截器
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//获取当前拦截器
Interceptor interceptor = interceptors.get(index);
//调用当前拦截器的intercept并传入下一个拦截器
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
}
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//1 Request阶段,该拦截器在Request阶段负责做的事情
//2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
//3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
return response;
}
}
- 在当前链元素的proceed()中会构造下一个链元素next,并获取到当前链元素的拦截器interceptor,调用拦截器的interceptor.intercept(next);将next传进去。
- 在intercept(next)继续会调用next的proceed()直到最后一个CallServerInterceptor。在该拦截其中没有调用next的proceed()
- 最后将Response逐级返回。
- 它的实现采用责任链模式
- 它们的功能如下
- RetryAndFollowUpInterceptor:负责重定向。
- BridgeInterceptor:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。
- CacheInterceptor:负责读取缓存以及更新缓存。
- ConnectInterceptor:负责与服务器建立连接。
- CallServerInterceptor:负责从服务器读取响应的数据。
从上面的描述可知,Request是按照interpretor的顺序正向处理,而Response是逆向处理的。这参考了OSI七层模型的原理。上面我们也提到过。CallServerInterceptor相当于最底层的物理层,
请求从上到逐层包装下发,响应从下到上再逐层包装返回。很漂亮的设计。
- 位置决定功能,位置靠前的先执行,最后一个则复制与服务器通讯,请求从RetryAndFollowUpInterceptor开始层层传递到CallServerInterceptor,每一层
都对请求做相应的处理,处理的结构再从CallServerInterceptor层层返回给RetryAndFollowUpInterceptor,最红请求的发起者获得了服务器返回的结果。- 以上便是Okhttp整个请求与响应的具体流程,可以发现拦截器才是Okhttp核心功能所在,我们来逐一分析每个拦截器的实现。
参考
https://juejin.im/post/5a704ed05188255a8817f4c9