1、OkHttp请求整体流程是怎样的
- 构建
OkhttpClient
对象 - 构建
Request
对象 - Request传入到
newCall方法
生成Realcall
对象,用它来发起新请求 分发器
维护请求队列和线程池,完成请求调配- 同步-》realcall中的execute方法,client.dispatcher().executed(this);执行runningSyncCalls.add(call); 再执行getResponseWithInterceptorChain
- 异步-》realcall中的enqueue方法,client.dispatcher().enqueue(new AsyncCall(responseCallback));分发器中加到异步请求队列。再线程池请求,最终调用到getResponseWithInterceptorChain
- 执行
getResponseWithInterceptorChain
跑到拦截器
- 执行chain.proceed(originalRequest)返回结果
Response
2、分发器是如何工作的?
2.1 同步
-
Realcall.execute() 会跑到分发器Dispatcher.java 执行execute()
-
加到runningSyncCalls也就是同步线程队列中
-
调用getResponseWithInterceptorChain()运行拦截器用的责任链模式,
最终返回Response
-
用完移除RealCall 调用client.dispatcher().finished(this);
java
-------------Realcall.java
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
//1、 分发器执行execute 传入
client.dispatcher().executed(this);
// 2、执行getResponseWithInterceptorChain()
return getResponseWithInterceptorChain();
} finally {
//3、用完移除RealCall
client.dispatcher().finished(this);
}
}
JAVA
-------------Dispatcher.java
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
2.2 异步
2.2.1 异步执行流程
- Realcall.enqueue(new AsyncCall())
- 请求数不超过64,且同一host请求不能超过5个。
- 加入到runningAsyncCalls
- 加入到线程池中中执行,executorService().execute(call);
- 每个任务完成后,都会调用分发器的
finished
方法,这里面会取出等待队列readyAsyncCalls中的任务继续执行
- 否则加入到等待队列readyAsyncCalls中
java
-------------Dispatcher.java
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);
}
}
2.2.2 异步AysncCall类分析
- AysncCall继承了抽象类NamedRunnable,线程池最终会跑AysncCall的run方法,执行到了AysncCall的execute方法,跑到
getResponseWithInterceptorChain()
;
java
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
...
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
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 {
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
}
JAVA
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
3、拦截器如何工作?
-
责任链设计是 将
请求者
与执行者
进行解耦
,请求发了,不用关心细节。这个链上的每一个节点都有机会处理请求,处理完了交给下一个,呈一个U形结构。如下图所示。CallServerInterceptor
的intercept
方法,此方法会将网络响应的结果封装成一个Response
对象并return
-
- 应用拦截器(用户可自定义)
- 拿到最原始请求,可以添加自定义header、通用参数等
- 重试重定向拦截器
- 处理错误重试和重定向
- 桥接拦截器
- 应用层和网络层的桥接拦截器,主要工作是条件cookie、固定和header,保存结果的cookie,如响应用过gzip压缩过,就还需要解压
- 缓存拦截器
- 如果命中缓存则不会发起网络请求
- 连接拦截器
- 内部维护一个连接池,负责连接服用、创建连接(3次握手)、释放连接以及创建连接上的socket流
- 网络拦截器(用户可自定义)
- 通常用于检测网络层的数据连接
- 请求服务拦截器
- 前置准备工作完成后,真正发起网络请求
- 应用拦截器(用户可自定义)
java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}