本篇文章主要介绍OkHttp从发起请求到接收到结果的整个执行流程. 由上篇的概述可知,OkHttp支持同步和异步的请求,这里我们以异步请求为例进行分析
一,异步OkHttp请求示例
private void testOkHttp() throws IOException {
final OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder().url("https://www.google.com.hk").build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.i(TAG,response.toString());
Log.i(TAG,response.body().string());
}
});
}
上面的代码就实现了一个网络请求. 创建一个OkHttpClient对象,他包含了分发器,连接池,拦截器等等内容. 接下来创建一个请求对象,通过OkHttpClient的newCall()方法对其包装,然后添加请求队列,然后回调结果
Tip
对于OkHttpClient封装一个单实例,让所有的Http请求都重用它, OkHttp将会有更好的性能.因为每一个OkHttpClient实例都持有自己的连接池,线程池等,重用连接池和线程池能够减少网络访问延迟以及节省内存,减少资源的浪费
下面我们就详细的分析一下OkHttp详细的网络访问流程
二,OkHttp详访流程
1,创建HttpClient对象.
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
... ...
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
由上面可知HttpClient创建的时候,初始化了连接池,线程池,默认拦截器等等,为接下来的网络请求铺垫
2,创建Request对象
Request request = new Request.Builder().url("https://www.google.com.hk").build();
通过Request中的Builder构建一个请求对象
这个Request对象我们可以理解成一个请求Bean,里面封装了请求的url, 请求方法(post get put delete等),请求头,请求体,以及tag(用于批量取消)
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
接下来继续对Request对象进行包装,使其能够执行execute,入队enqueue, 取消cancel, 判断状态 isCancel和isExecuted
上面的call指向的是RealCall对象
我们看下Call接口
public interface Call extends Cloneable {
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
3,将请求入队
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
OkHttpClient的dispatcher()方法返回的是一个Dispatcher对象,每个Dispatcher使用线程池来运行上面的Call任务.
接下来我们看下Dispacher的入队操作
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
runningAsyncCalls存放所有正在执行的异步任务
readyAsyncCalls存放所有正在等待执行的异步任务
当正在执行的请求小于最大请求数64且每个主机的最大请求数不超过5 则直接加入到正在执行的异步队列中且执行.
否则加入到正在等待执行的异步队列中等待执行.
**由上我们可知
请求相同主机的最大请求数目是5
所有请求最大数目是64
实际开发中,用户量一般的app服务器只有一个,那么一般最大的请求就是5
**
好了,一个请求封装准备了这么多, 顺利入队,下面我们看看他下面是怎么执行的
4,执行
RealCall封装了原始的Request,在RealCall中有一个非静态内部类AsyncCall,AsyncCall中的execute方法就是任务要执行的代码
final class AsyncCall extends NamedRunnable {
... ...
... ...
@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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
通过getResponseWithInterceptorChain方法 获取到Response对象,下面我们看下他的拦截链
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> 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);
return chain.proceed(originalRequest);
}
RealInterceptorChain.java
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
... ...
//取出下一个拦截器,递归调用
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
... ...
return response;
}
1)首先添加用户自定义的拦截器(如果有),接着依次添加重试拦截器,桥接拦截器,缓存拦截器,连接拦截器以及访问服务器的拦截器.
这些拦截器的添加顺序是固定的,不能改变
2)这些拦截器形成一个拦截链,每个拦截器专司其自己的职责, 将处理好的请求交给下一个拦截器,最后一个拦截器处理完毕后,再将其交给上一个拦截器,直到第一个, 最后将结果返回.这样一个责任链就形成了
3)每个拦截器都实现Interceptor接口
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
4)对于拦截器之间的调用过程可能不太容易理解,下面针对2)给出一个示意图
Req: 请求Request缩写
Res: 响应Response缩写
5,结果回调
我们再将目光回到AsyncCall类
@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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
当通过getResponseWithInterceptorChain()一系列的处理得到结果后.
1),会首先判断结果是否取消, 如果取消则回调传入的回调onFail中
否则,回调结果到onResponse中
2),接下来是扫尾操作
调用Dispatcher的finish方法
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
它主要做了两件事儿
A,将刚才已经完成的任务从runningAsyncCalls移除
B,如果runningAsyncCall小于5(每个主机的最大访问数量), 则从readyAsyncCalls移除添加到runningAsyncCalls中,并且执行
至此一个完整的OkHttp异步请求完毕
总的来说: 就是根据请求的url, 请求方法, 请求体构造一个Request的Bean, 然后将Request封装成一个RealCall,RealCall实现了Call接口,他有对执行逻辑的操作(取消,执行,判断执行的状态等), 接下来通过全局的OkHttpClient(拥有线程池,连接池,分发器等资源),利用分发器Dispatcher加入到执行队列或者等待队列中.
然后线程池执行RealCall的非静态内部类AsyncCall的execute方法, 然后通过getResponseWithInterceptorChain来进行一系列的拦截器操作处理,回调请求结果.
最后进行扫尾操作,移除正在执行队列的当前请求,将等待队列的请求添加到执行队列.
OkHttp的处理核心是在拦截器,每个拦截器都有自己的职责,下一篇文章详细分析各个拦截器具体都干了什么
OkHttp之拦截器(二)