在Android开发中,当下最火的网络请求框架莫过于okhttp和retrofit,它们都是square公司的产品,两个都是很是优秀开源库,值得咱们去阅读它们的源码,学习它们的设计理念,但其实retrofit底层仍是用okhttp来发起网络请求的,因此深刻理解了okhttp也就深刻理解了retrofit,它们的源码阅读顺序应该是先看okhttp,我在retrofit上发现它最近的一次提交才把okhttp版本更新到3.14,okhttp目前最新的版本是4.0.x,okhttp从4.0.x开始采用kotlin编写,在这以前仍是用java,而我本次分析的okhttp源码版本是基本3.14.x,看哪一个版本的不重要,重要的是阅读事后的收获,我打算分2篇文章去分析okhttp,分别是:java
本文是第一篇 - okhttp的请求流程,okhttp项目地址:okhttpgit
咱们经过一个简单的GET请求来回忆一下okhttp的使用步骤,并以这个实例为例讲解okhttp的请求流程,以下:github
//一、建立OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build();
//二、建立请求Request
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
//三、建立一个Call,用于发起网络请求
Call call = client.newCall(request);
//四、发起GET请求
//4.一、同步请求,调用Call的execute()方法
try {
//接收到回复Response
Response response = call.execute();
Log.d(TAG, response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
//4.二、异步请求, 调用Call的enqueue()方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//接收到回复Response
Log.d(TAG, response.body().string());
}
});
复制代码
能够看到,使用okhttp发起网络请求要通过4步:web
当服务器处理完一个请求Request后,就会返回一个响应,在okhttp中用Response表明HTTP的响应,这就是一个典型的HTTP请求/响应流程。下面简单介绍1~3步骤:缓存
OkHttpClient是okhttp中的大管家,它将具体的工做分发到各个子系统中去完成,它使用Builder模式配置网络请求的各类参数如超时、拦截器、分发器等,Builder中可配置的参数以下:安全
//OkHttpClient.Builder
public static final class Builder {
Dispatcher dispatcher;//分发器
@Nullable Proxy proxy;//代理
List<Protocol> protocols;//应用层协议
List<ConnectionSpec> connectionSpecs;//传输层协议
final List<Interceptor> interceptors = new ArrayList<>();//应用拦截器
final List<Interceptor> networkInterceptors = new ArrayList<>();//网络拦截器
EventListener.Factory eventListenerFactory;//http请求回调监听
ProxySelector proxySelector;//代理选择
CookieJar cookieJar;//cookie
@Nullable Cache cache;//网络缓存
@Nullable InternalCache internalCache;//内部缓存
SocketFactory socketFactory;//socket 工厂
@Nullable SSLSocketFactory sslSocketFactory;//安全套接层socket 工厂,用于HTTPS
@Nullable CertificateChainCleaner certificateChainCleaner;//验证确认响应证书,适用 HTTPS 请求链接的主机名
HostnameVerifier hostnameVerifier;//主机名字确认
CertificatePinner certificatePinner;//证书链
Authenticator proxyAuthenticator;//代理身份验证
Authenticator authenticator;//本地身份验证
ConnectionPool connectionPool;//链接池,复用链接
Dns dns;//域名
boolean followSslRedirects;//安全套接层重定向
boolean followRedirects;//本地重定向
boolean retryOnConnectionFailure;//错误重连
int callTimeout;//请求超时,它包括dns解析、connect、read、write和服务器处理的时间
int connectTimeout;//connect超时
int readTimeout;//read超时
int writeTimeout;//write超时
int pingInterval;//ping超时
//这里是配置默认的参数
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;//Protocol.HTTP_2和Protocol.HTTP_1_1
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
//这里经过另一个OkHttpClient配置参数
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
//...
}
//...
//配置完参数后,经过Builder的参数建立一个OkHttpClient
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
复制代码
在okhttp中Request表明着一个HTTP请求,它封装了请求的具体消息,如url、header、body等,它和OkHttpClient同样都是使用Budiler模式来配置本身的参数,以下:服务器
//Request.Budiler
public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;
//这里配置默认的参数
public Builder() {
this.method = "GET";//默认是GET请求
this.headers = new Headers.Builder();
}
//这里经过另一个Request配置参数
Builder(Request request) {
this.url = request.url;
this.method = request.method;
//...
}
//...
//配置完参数后,经过Builder的参数建立一个Request
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
}
复制代码
Call是一个接口,它的具体实现类是RealCall,Call中定义了一些enqueue(Callback)、
execute()等关键方法,以下:cookie
public interface Call extends Cloneable {
//返回当前请求
Request request();
//同步请求方法,此方法会阻塞当前线程直到请求结果放回
Response execute() throws IOException;
//异步请求方法,此方法会将请求添加到队列中,而后等待请求返回
void enqueue(Callback responseCallback);
//取消请求
void cancel();
//判断请求是否在执行
boolean isExecuted();
//判断请求是否取消
boolean isCanceled();
//返回请求的超时时间
Timeout timeout();
//克隆一个新的请求
Call clone();
interface Factory {
Call newCall(Request request);
}
}
复制代码
咱们看到Call接口中有一个Factory接口,Factory中有一个newCall(Request)方法,这说明Call是经过工厂模式建立,而OkHttpClient实现了Call.Factory接口,重写了newCall(Request)方法,返回了Call的具体实现类RealCall,以下:网络
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
//...
@Override
public Call newCall(Request request) {
//调用了RealCall的newRealCall()
return RealCall.newRealCall(this, request, false /* for web socket */);
}
}
final class RealCall implements Call {
//...
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//返回RealCall对象
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
}
复制代码
因此调用**client.newCall(request)**其实返回的是RealCall对象,而RealCall封装了请求的调用逻辑。框架
到这里也就走到了注释4,也就是第4步,okhttp经过Call的实现类RealCall的execute()或enqueue()方法发起同步或异步请求,也就是本文的重点,下面分别详细介绍:
//RealCall.java
@Override
public Response execute() throws IOException {
//...
try {
//一、调用Dispatcher的executed(RealCall)方法
client.dispatcher().executed(this);
//二、调用getResponseWithInterceptorChain()方法
return getResponseWithInterceptorChain();
} finally {
//三、同步请求任务执行完毕,调用Dispatcher的finished(RealCall)方法
client.dispatcher().finished(this);
}
}
复制代码
client就是咱们上面所讲的OkHttpClient的实例,它在建立RealCall时做为构造参数传了进去,而OkHttpClient的dispatcher()方法返回的是Dispatcher实例,它在OkHttpClient构造时被建立。
咱们先讲一下Dispatcher,那Dispatcher是什么呢?Dispatcher是一个任务调度器,它负责进行请求任务的调度,它的内部维护着3个任务队列(readyAsyncCalls、runningAsyncCalls、runningSyncCalls)和1个线程池(executorService),Dispatcher主要内容以下:
public final class Dispatcher {
private int maxRequests = 64;//最大请求数64个
private int maxRequestsPerHost = 5;//每一个主机最大请求数5个
private @Nullable Runnable idleCallback;//idle任务回调,相似于Android的idlehandler, 能够在Dispatcher没有任务调度(空闲时)时执行idleCallback中的任务
//线程池,执行runningAsyncCalls队列里面的请求任务
private @Nullable ExecutorService executorService;
//等待执行的异步请求任务队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在执行的异步请求任务队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在执行的同步请求任务队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
synchronized void executed(RealCall call) {
//...
}
void enqueue(AsyncCall call) {
//...
}
void finished(RealCall call) {
//...
}
void finished(AsyncCall call) {
//...
}
private boolean promoteAndExecute() {
//...
}
//...
}
复制代码
Dispatcher提供了executed(RealCall)和enqueue(AsyncCall)方法来进行同步和异步请求任务的入队,还提供了finished(RealCall)和finished(AsyncCalll)方法来进行同步和异步请求任务的出队,能够看到okhttp把ReadCall看成同步请求任务的表明,把AsyncCall看成异步请求任务的表明,RealCall前面已经讲过了,而AsyncCal是RealCall的一个内部类,它本质上就是一个Runnable,Dispatcher的线程池执行任务主要执行的是runningAsyncCalls队列里面的异步请求任务,也就是AsyncCall异步任务,而Dispatcher的promoteAndExecute()方法就是用来进行异步任务的调度,它的逻辑主要是按顺序把readyAsyncCalls队列中准备执行的异步任务转移到runningAsyncCalls后,再由线程池执行,对于同步任务Dispatcher只是暂时保存在runningSyncCalls队列中,并不会由线程池执行。
咱们继续回到RealCall的execute()方法,根据注释一、二、3分为3部分解释同步请求流程,以下:
看RealCall的execute()方法的注释1,它首先调用了Dispatcher的executed(RealCall)方法,Dispatcher的executed(RealCall)方法实现以下:
//Dispatcher.java
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
复制代码
能够看到没有作什么处理,只是简单的把同步请求任务放入runningSyncCalls队列。
看RealCall的execute()方法的注释2,调用getResponseWithInterceptorChain()方法,这里才是同步请求处理的地方,咱们点进去,以下:
//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
//拦截器的添加
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());
}
//添加的最后一个拦截器是CallServerInterceptor
interceptors.add(new CallServerInterceptor(forWebSocket));
//建立一个RealInterceptorChain,传入了interceptors和Request
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
try {
//调用RealInterceptorChain的proceed(Request)方法处理请求
Response response = chain.proceed(originalRequest);
//...
return response;
} catch (IOException e) {
//...
} finally {
//...
}
}
复制代码
getResponseWithInterceptorChain()方法最终返回一个Response,也就是网络请求的响应,该方法中首先把用户自定义的拦截器和okhttp默认的拦截器封装到一个List中,而后建立RealInterceptorChain并执行proceed(Request)方法处理请求,RealInterceptorChain的proceed(Request)方法以下:
//RealInterceptorChain.java
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
//...
//再新建一个RealInterceptorChain,这里注意index加1,
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
//获取interceptors列表中的下一个拦截器
Interceptor interceptor = interceptors.get(index);
//调用下一个拦截器的intercept(Chain)方法,传入刚才新建的RealInterceptorChain,返回Response
Response response = interceptor.intercept(next);
//...
return response;
}
复制代码
proceed()方法中再次新建了一个RealInterceptorChain,传入了index + 1,而获取拦截器时是经过index获取,这样每次都能获取到下一个拦截器,而后调用下一个拦截器的intercept(Chain)方法,intercept(Chain)方法中就是拦截器的主要功能实现,里面会继续调用传入的RealInterceptorChain的proceed()方法,这样又会重复上述逻辑,咱们把拦截器看做一条链中的节点,这样每一个拦截器就经过一个个RealInterceptorChain链接起来,造成一条链,这就是典型的责任链模式,从节点的首部开始把请求传递下去,每个拦截器都有机会处理这个请求,这又像是一个递归的过程,直到最后一个拦截器器处理完请求后,才开始逐层返回Resquese,拦截器才是Okhttp核心功能所在,关于拦截器介绍下篇文章再讲,这里只须要知道每个拦截器都表明了一个功能。
通过对拦截器的简单介绍后,咱们知道最后一个添加的拦截器才是把请求发送出去而且返回响应的地方,咱们看getResponseWithInterceptorChain()方法,最后一个拦截器的添加是CallServerInterceptor,因此咱们直接看CallServerInterceptor的intercept(Chain)方法实现,以下:
//CallServerInterceptor.java
@Override
public Response intercept(Chain chain) throws IOException {
//强转成RealInterceptorChain
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//获取Exchange
Exchange exchange = realChain.exchange();
//获取Request
Request request = realChain.request();
//一、经过Exchange的writeRequestHeaders(request)方法发送Request的header
exchange.writeRequestHeaders(request);
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
//由于前面已经讲了,默认是GET请求,而GET请求是没有body的,因此不会进入if分支
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//省略的是发送Request的body过程
//...
} else {
exchange.noRequestBody();
}
//GET请求body为空,进入这个分支,完成请求
if (request.body() == null || !request.body().isDuplex()) {
exchange.finishRequest();
}
//省略的是一些监听回调
//...
//下面开始获取网络请求返回的响应
//二、经过Exchange的readResponseHeaders(boolean)方法获取响应的header
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(false);
}
//获取响应后,经过Builder模式构造Response
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//省略的是response对状态码code的处理
//...
//构造Response的body
if (forWebSocket && code == 101) {
//构造一个空的body的Response
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//经过Exchange的openResponseBody(Response)方法获取响应的body,而后经过响应的body继续构造Response
response = response.newBuilder()
.body(exchange.openResponseBody(response))
.build();
}
//...
//返回响应Response
return response;
}
复制代码
intercept(Chain)方法中主要作的就是发送请求,获取响应的事情,注释中已经写的很清楚了,发送请求要把header和body分开发送,而获取响应时也要分别获取header和body,而发送请求和获取响应两个过程都是经过一个Exchange对象进行的,Exchange是在构造RealInterceptorChain时就做为构造参数传进RealInterceptorChain中,一直都为null,直到在ConnectInterceptor的intercept()中才经过Transmitter的newExchange()被赋值,而ConnectInterceptor的下一个拦截器就是CallServerInterceptor,因此CallServerInterceptor能够经过Chain获取到Exchange实例,这里不用细究这个赋值过程,Exchange它主要是用来负责完成一次网络请求和响应的过程。
这里我以intercept(Chain)方法中注释1和注释2请求header的发送(wirte)和获取(read)为例了解Exchange的工做过程,首先看Exchange的writeRequestHeaders(Request)方法,以下:
//Exchange.java
public void writeRequestHeaders(Request request) throws IOException {
try {
//主要是调用了codec的writeRequestHeaders(request)
codec.writeRequestHeaders(request);
//...
} catch (IOException e) {
//...
}
}
复制代码
咱们再看Exchange的readResponseHeaders(boolean)方法,以下:
//Exchange.java
public @Nullable Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {
try {
//主要是调用了codec的readResponseHeaders(boolean)
Response.Builder result = codec.readResponseHeaders(expectContinue);
//...
return result;
} catch (IOException e) {
//...
}
}
复制代码
从Exchange的两个方法能够看出,它把 wirt和read header的任务都交给了codec,codec是什么呢?codec是ExchangeCodec类型,它是一个接口,它主要用来编码http请求并解码http返回结果,因此Exchange中真正干活的是ExchangeCodec,它的有两个实现类,分别是Http2ExchangeCodec和Http1ExchangeCodec,分别对应Http2.x和Http1.x,这里咱们以Http1ExchangeCodec为例,查看它的writeRequestHeaders(request)和readResponseHeaders(boolean)方法,首先看Http1ExchangeCodec的writeRequestHeaders(request)方法,以下:
//Http1ExchangeCodec.java
@Override
public void writeRequestHeaders(Request request) throws IOException {
String requestLine = RequestLine.get(
request, realConnection.route().proxy().type());
//调用了writeRequest()
writeRequest(request.headers(), requestLine);
}
public void writeRequest(Headers headers, String requestLine) throws IOException {
if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
//能够看到经过sink把请求头写入IO流,发送到服务器,sink是BufferedSink类型
sink.writeUtf8(requestLine).writeUtf8("\r\n");
for (int i = 0, size = headers.size(); i < size; i++) {
sink.writeUtf8(headers.name(i))
.writeUtf8(": ")
.writeUtf8(headers.value(i))
.writeUtf8("\r\n");
}
sink.writeUtf8("\r\n");
state = STATE_OPEN_REQUEST_BODY;
}
复制代码
咱们再看Http1ExchangeCodec的readResponseHeaders(boolean)方法,以下:
//Http1ExchangeCodec.java
@Override
public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {
//...
try {
StatusLine statusLine = StatusLine.parse(readHeaderLine());
Response.Builder responseBuilder = new Response.Builder()
.protocol(statusLine.protocol)
.code(statusLine.code)
.message(statusLine.message)
.headers(readHeaders());//调用了readHeaders()
//...
return responseBuilder;
} catch (EOFException e) {
//...
}
}
private Headers readHeaders() throws IOException {
Headers.Builder headers = new Headers.Builder();
//调用了readHeaderLine(),一行一行的读取header
for (String line; (line = readHeaderLine()).length() != 0; ) {
Internal.instance.addLenient(headers, line);
}
return headers.build();
}
private String readHeaderLine() throws IOException {
//服务器响应返回,经过source从IO读取响应头,source是BufferedSource类型
String line = source.readUtf8LineStrict(headerLimit);
headerLimit -= line.length();
return line;
}
复制代码
从Http1ExchangeCodec的两个方法能够看出,底层是经过BufferedSink把信息写入IO流,经过BufferedSource从IO流读取信息,BufferedSink和BufferedSource都是来自okio这个开源库的,okhttp底层是经过okio来向网络中写入和读取IO的,想要了解更多可自行查看okio源码(okio也是square公司的产品)。
到此RealCall的 getResponseWithInterceptorChain()分析完,getResponseWithInterceptorChain()返回Response后,RealCall的execute() 方法就return了,咱们就能够经过返回的Response获取咱们想要的信息,但RealCall的execute() 方法就return后,还要继续执行finally 分支中的逻辑。
咱们继续看RealCall的execute()方法的注释3,调用Dispatcher的finished(AsyncCall)方法,以下:
//Dispatcher.java
void finished(RealCall call) {
//传进了runningSyncCalls队列
finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
//尝试移除队列中的同步请求任务
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
//紧接着调用promoteAndExecute()方法进行异步任务的调度,若是没有异步任务要进行,promoteAndExecute()返回false
boolean isRunning = promoteAndExecute();
//isRunning等于false且设置了idleCallback,会执行一遍idle任务
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
复制代码
finished()方法中首先尝试从runningSyncCalls队列把刚才经过 executed()入队的同步任务RealCall移除,若是移除失败,就抛出异常,若是移除成功,就紧接着调用promoteAndExecute()方法进行异步任务的调度并尝试执行一遍idle任务,promoteAndExecute()方法在异步请求中再详细介绍。
至此okhttp的同步请求过程分析完毕,这里总结一下:当咱们调用call.execute()时,就会发起一个同步请求,而call的实现类是RealCall,因此实际执行的是realCall.execute(),realCall.execute()中执行Dispatcher的executed(RealCall)把这个同步请求任务保存进runningSyncCalls队列中,而后RealCall执行getResponseWithInterceptorChain()处理同步请求,请求通过层层拦截器后到达最后一个拦截器CallServerInterceptor,在这个拦截器中经过Exchange把请求发送到服务器,而后一样的经过Exchange得到服务器的响应,根据响应构造Response,而后返回,最后RealCall执行Dispatcher的finished(RealCall)把以前暂时保存的同步请求任务从runningSyncCalls队列中移除。
下面是同步请求过程的调用链:
//RealCall.java
@Override
public void enqueue(Callback responseCallback) {
//...
//一、调用Dispatcher的enqueue(AsyncCall)方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
复制代码
异步请求执行的是RealCall的enqueue(Callback)方法,它比同步请求只是多了一个Callback,在Callback的 onResponse(Call, Response)回调中咱们能够拿到网络响应返回的Response,RealCall的enqueue(Callback)方法中首先把Callback用AsyncCall包装起来,而后调用调用Dispatcher的enqueue(AsyncCall)方法。
咱们看Dispatcher的enqueue(AsyncCall)方法,以下:
//Dispatcher.java
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
//...
}
promoteAndExecute();
}
复制代码
该方法首先把异步请求任务AsyncCall放入readyAsyncCalls队列,而后调用promoteAndExecute()进行异步任务的调度,咱们看一下Dispatcher 是如何进行异步任务的调度的。
promoteAndExecute()方法以下:
//Dispatcher.java
private boolean promoteAndExecute() {
//准备一个正在执行任务列表executableCalls
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//一、这个for循环主要把readyAsyncCalls中等待执行的异步任务转移到runningAsyncCalls队列和executableCalls列表中去
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
//取出readyAsyncCalls中等待执行的异步任务
AsyncCall asyncCall = i.next();
//判断条件:一、正在运行的异步请求任务不能大于maxRequests;二、等待执行的异步任务的主机请求数不能大于maxRequestsPerHost
if (runningAsyncCalls.size() >= maxRequests) break;
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue;
//知足条件,进入下面逻辑
//把这个等待执行的异步任务从readyAsyncCalls中移除
i.remove();
asyncCall.callsPerHost().incrementAndGet();
//把这个等待执行的异步任务添加进executableCalls列表
executableCalls.add(asyncCall);
//把这个等待执行的异步任务添加进runningAsyncCalls队列
runningAsyncCalls.add(asyncCall);
}
//runningCallsCount()里面的逻辑: return runningAsyncCalls.size() + runningSyncCalls.size();
isRunning = runningCallsCount() > 0;
}
//二、这个for循环主要是执行executableCalls列表中的异步任务
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//传进executorService,调用AsyncCall的executeOn()方法,由线程池执行这个异步任务
asyncCall.executeOn(executorService());
}
return isRunning;
}
复制代码
promoteAndExecute()方法中主要是2个for循环,注释1的第一个for循环是把符合条件的异步请求任务从readyAsyncCalls转移(提高)到runningAsyncCalls队列和添加到executableCalls列表中去,紧接着注释2的第二个for循环就是遍历executableCalls列表,从executableCalls列表中获取AsyncCall对象,而且调用它的executeOn()方法,executeOn()方法传进了一个Dispatcher的executorService,因此咱们看AsyncCall的executeOn()方法,里面是真正执行异步请求任务的地方。
AsyncCall的executeOn()方法以下:
//AsyncCall.java
void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//传进this,执行AsyncCall异步任务,AsyncCall本质是Runnable
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
//...
} finally {
if (!success) {
//异步任务执行失败,调用Dispatcher的finished(AsyncCall)方法
client.dispatcher().finished(this);
}
}
复制代码
能够看到,里面的主要逻辑就是调用 executorService.execute(this)执行当前的AsyncCall异步任务,前面已经说过AsyncCall实现了NamedRunnable,本质是Runnable,以下:
final class AsyncCall extends NamedRunnable {
//...
}
public abstract class NamedRunnable implements Runnable {
//...
@Override
public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//run方法中执行execute()方法
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
复制代码
线程池执行到此异步任务时,它的run方法就会被执行,而run方法主要调用execute()方法,而execute()方法是一个抽象方法,AsyncCall实现了NamedRunnable,因此AsyncCall重写了execute()实现了执行逻辑,因此咱们直接看AsyncCal的execute()方法。
AsyncCal的execute()方法以下:
//AsyncCall.java
@Override
protected void execute() {
//...
try {
//调用RealCall的getResponseWithInterceptorChain()方法处理请求
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
//请求处理完毕,返回响应,回调Callback的onResponse()方法
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
//...
} finally {
//异步请求任务执行完毕,调用Dispatcher的finished(AsyncCall)方法
client.dispatcher().finished(this);
}
}
复制代码
AsyncCal的execute()方法的逻辑和前面介绍的同步请求过程异曲同工,首先调用RealCall的getResponseWithInterceptorChain()方法处理请求,请求处理完毕后,返回响应Response,这时回调咱们调用Call.enqueue(Callback)时传进来的Callback的onResponse()方法,最后在finally语句中调用Dispatcher的finished(AsyncCall)方法来把异步请求任务从runningAsyncCalls队列中移除出去,这个移除逻辑和上面同步请求任务的移除逻辑同样,只是此次是从runningAsyncCalls移除而不是runningSyncCalls,以下:
//Dispatcher.java
void finished(AsyncCal call) {
//传进runningAsyncCalls,而不是runningSyncCalls
finished(runningSyncCalls, call);
}
复制代码
至此okhttp的异步请求过程分析完毕,这里再次总结一下,当咱们调用call.enqueue(Callback)时,就会发起一个异步请求,实际执行的是realCall.enqueue(Callback),它比同步请求只是多了一个Callback参数,而后realCall.execute()中先把传进来的Callback包装成一个AsyncCall,而后执行Dispatcher的enqueue(AsyncCall)把这个异步请求任务保存进readyAsyncCalls队列中,保存后开始执行 promoteAndExecute()进行异步任务的调度,它会先把符合条件的异步请求任务从readyAsyncCalls转移到runningAsyncCalls队列和添加到executableCalls列表中去,而后遍历executableCalls列表,逐个执行AsyncCall 的executeOn(ExecutorService),而后在这个方法中AsyncCall会把本身放进Dispatcher 的线程池,等待线程池的调度,当线程池执行到这个AsyncCall时,它的run方法就会被执行,从而执行重写的execute()方法,execute()方法中的流程和同步请求流程大体相同。
下面是异步请求过程的调用链:
okhttp经过Builder模式建立OkHttpClient、Request和Response,经过client.newCall(Resquest)建立一个Call,用于发起异步或同步请求,请求会通过Dispatcher、一系列拦截器,最后经过okio与服务器创建链接、发送数据并解析返回结果,这个过程如图:
以上就是对okhttp的请求流程的分析,若有错误,欢迎指出。
参考文章: