OkHttp简介
OkHttp工作的流程图
此图片来源:https://blog.piasy.com/2016/07/11/Understand-OkHttp/
OkHttp源码解析
这里以get方式为例说明:
//第一步:创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//第二步:创建请求
Request request = new Request.Builder().url("url").build();
//第三步:发送请求,同步执行
okHttpClient.newCall(request).execute();
第一步:创建OkHttpClient对象
/**
点进来查看,显示如下
*/
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.connectionPool = builder.connectionPool;
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
......
}
第二步:创建请求
//初始化构建者模式和请求对象,且用URL替换Web套接字URL,支持http和https
public final class Request {
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(String url) {
......
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
HttpUrl parsed = HttpUrl.parse(url);
......
return url(parsed);
}
public Request build() {
......
return new Request(this);
}
}
第三步:发送请求,执行请求
okHttpClient调用newCall方法,传入request对象,先来看newCall方法源码
/**
OkHttpClient 实现了 Call.Factory,负责根据请求创建新的 Call,callFactory 负责创建 HTTP 请求,
HTTP请求被抽象为了 okhttp3.Call 类,它表示一个已经准备好,可以随时执行的 HTTP 请求
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false);
}
再来看newRealCall方法
static RealCall newRealCall(OkHttpClient client, Request
originalRequest, boolean forWebSocket) {
/** 创建请求Call */
RealCall call = new RealCall(client, originalRequest,
forWebSocket);
/** 将Call安全的添加到事件监听中,使事件的分发和流程控制变得更为简便*/
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
可以看到主要逻辑在RealCall方法中,我们接着看
private RealCall(OkHttpClient client, Request originalRequest,
boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
/**拦截器,其主要作用是进行请求的重试与重定向*/
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
上述中有 okHttpClient.newCall(request).execute( ) ,所以此处查看RealCall#execute方法
//同步请求方法
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already
Executed"); //(1)
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
//同步,把这次请求添加到分发器中,就是上述中应用层中的分发器
client.dispatcher().executed(this); //(2)
//截获器处理
Response result = getResponseWithInterceptorChain(); //(3)
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this); //(4)
}
}
(1) 检查这个 call 是否已经被执行了,每个 call 只能被执行一次,如果想要一个完全一样的 call,可以利用call#clone
方法进行克隆
(2) 调用分发器实际执行,进入client.dispatcher().executed(this)方法中查看,详情见于OkHttp源码分析(二)分发器Dispatcher介绍
/**将当前的Call添加到执行队列中*/
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
(3) 接下来看截获器getResponseWithInterceptorChain()源码,
/**
调用 getResponseWithInterceptorChain() 函数获取 HTTP 返回结果,其中会再次经过拦截
*/
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
/**
Interceptor 是 OkHttp 最核心的一个东西,它把实际的网络请求、缓存、透明压缩等功能都统一了起来,
每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完
成一次网络请求.这个Interceptor链条是典型的“责任链模型”,对于把 Request 变成 Response 这件
事来说,每个 Interceptor 都可能完成这件事,我们循着链条让每个 Interceptor 自行决定能否完成
任务以及怎么完成任务(自力更生或者交给下一个Interceptor)。这样一来,完成网络请求这件事就彻底
从 RealCall 类中剥离了出来,简化了各自的责任和逻辑
*/
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));
........
}
流程图表示:
- interceptors:配置OkHttpClient时设置
- RetryAndFollowUpInterceptor:失败重试及重定向时使用
- BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应
- CacheInterceptor:负责读取缓存直接返回、更新缓存
- ConnectInterceptor:负责和服务器建立连接
- networkInterceptors:配置OkHttpClient时设置
- CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据
(4)最后通知 dispatcher 自己已经执行完毕
上面设置完所有的截获器之后,最终要串成一个Interceptor.Chain,如下所示
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
接着看RealInterceptorChain#proceed()源码,
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
........
/**不断的递归遍历判断是否每个拦截器都有对应的处理,若是没有的话先新建RealInterceptorChain,
并执行当前的intercept方法,拦截器可以用来转换,重试,重写请求的机制
*/
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
.......
return response;
}
//使用方法
okHttpClient.newBuilder().addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
.addHeader("test","testValue")
.build();
return chain.proceed(request);
}
});
以上是同步执行excute的解析,现就异步请求enqueue做简要说明
synchronized void enqueue(AsyncCall call) {
/**
maxRequests:最大并发请求数,默认为64
maxRequestsPerHost:每个主机最大请求数,默认为5
runningAsyncCalls:正在执行的异步请求,包含已经取消但未执行完的请求
readyAsyncCalls:准备执行的请求
*/
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//判断是否超过阈值,若是没有则添加到执行的队列runningAsyncCalls中
runningAsyncCalls.add(call);
//线程池中执行这个call
executorService().execute(call); //(1)
} else {
//若是超过,则添加到等待的队列readyAsyncCalls中
readyAsyncCalls.add(call);
}
}
(1)同步请求和异步请求的原理是一样的,现executorService().execute(call)中传入的是AsyncCall,进入查看其源码:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
//构造方法传入Callback 类型 ---------------------(2)
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
........
//执行execute方法
@Override protected void execute() { ------------------------(3)
boolean signalledCallback = false;
try {
/**此处我们看到同步和异步都会调用getResponseWithInterceptorChain()函数中通过 Interceptor 链条
来实现的网络请求逻辑,这就和我们最上面的“OkHttp工作的流程图”中的模型对接上了
*/
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);
}
}
}
(2) AsyncCall构造方法中的参数Callback 源码如下:
//这就是为什么异步执行的时候有回调,同步执行的时候没有回调,原因是异步执行的时候传入了接口
public interface Callback {
void onFailure(Call call, IOException e);
void onResponse(Call call, Response response) throws IOException;
}
(3) 由于AsyncCall继承NamedRunnable类,而execute方法是NamedRunnable中的抽象类,所以必须重写:
//可以看出NamedRunnable实现Runnable接口,是一个子线程
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();
}
至此关于OkHttp异步和同步的执行流程分析完毕,其发送请求和接收返回数据的相关分析请见OkHttp源码分析(三)拦截器