前两两片我们介绍了,基本使用和如何查看源码,今天我们正式进入源码分析流程。
首先我们先看一看它的请求流程,在Okhttp3中请求是基于拦截器原理,源代码如下:
源码路径:okhttp3/RealCall.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// 开始执行整个请求 Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. // 拦截器栈 List |
研究Okhttp3的源码,从此处开始,一个一个拦截器,读懂即可。不得不说这种方式真的很棒,清晰明了。
整体框架图(图片来源网络,感谢作者):
通过上图,想必对Okhttp3的实现方式,已经有了基本的认识下面我们就一步一具体分析。
HttpClient采用了建造者设计模式来实例化。本身有多个字段用于全局对象,比去Cache、Dns等
静态代码块构造全局缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
static { Internal.instance = new Internal() { // 略 public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) { // 写入缓存,指的是响应数据缓存 builder.setInternalCache(internalCache); } // 从缓存中获取有效的连接,仅支持Http/2, 本质就是从内存的ConnectiongPol中的Deque读取 public RealConnection get( ConnectionPool pool, Address address, StreamAllocation streamAllocation) { return pool.get(address, streamAllocation); } // 将连接缓存到连接池中 public void put(ConnectionPool pool, RealConnection connection) { pool.put(connection); } // 线路的缓存,多host多ip的青款 public RouteDatabase routeDatabase(ConnectionPool connectionPool) { return connectionPool.routeDatabase; } // 略 } // 此处有很多种数据缓存处理,不了解并不影响代码分析,如有兴趣可自行研究 |
Dispatcher, 分发请求,内部是有一个ThreadPoolExecutor
Proxy, 代理连接,分三种类型直接(DIRECT)、Http(http)、SOCKS。
ProxySelector,线路选择器,对应Okhttp的一大特点,自行线路选择,找到合适的连接
Cache, 真正的缓存实现
SSLSocketFactory, Https的支持
ConnectionPool, 连接池
Dns,dns解析(Java实现)
其他,如超时时间等
我们都知道一个请求有多部分组成,同样Okhttp3创建一个请求也要多部分。
通过以上三步我们就可以完成一次请求。
header并非每个请求都需要,要看与服务端是如何定义的,通常一个请求会默认一些头,比如Content-Type,Accept-Encoding,Connection等对应http协议
Header本质上就是一个Map,只是在封装了一层而已,但是Okhttp3的实现不是这样,而是一个String数据,key + value的形式,即一个头占用数组的两位:
每一个色块对应一个header,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
// 源码路径 okhttp3/Headers.java public final class Headers { private final String[] namesAndValues; // 略 Builder addLenient(String name, String value) { namesAndValues.add(name); namesAndValues.add(value.trim()); return this; } // 略 } |
请求体有多种形式,对应的父类是RequestBody,有文件形式、Json等,MediaType决定了是何种形式,通常我们用的是FromBody和MultipartBody
FromBody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public final class FormBody extends RequestBody { private static final MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded"); private final List |
MultipartBody
MultipartBody原理基本一致,区别在于他可以发送表单的同时也可以发送文件数据,再次不在赘述。
有了上面两个步骤,接下了就自然而让产生一个Request,顾名思义它就是对请求的封装,包括请求方式,请求头,请求体,请求路径等,源代码码也是比较简单,一看即明白。
1 2 3 4 5 6 7 |
public final class Request { final HttpUrl url; final String method; final Headers headers; final RequestBody body; final Object tag; } |
有了准备工作,现在我们就要发射了,Call是一个概念的封装,就像一列火车,蓄势待发,在铁轨停靠准备出发一样
Call是一个接口,实现类只有一个RealCall,上面我们提到的流程就是在RealCall中。
1 2 3 4 5 6 7 8 9 10 11 12 |
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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
// 重点看看中文注释处即可 final class RealCall implements Call { final OkHttpClient client; // 重试拦截器 final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor; /** The application's original request unadulterated by redirects or auth headers. */ final Request originalRequest; final boolean forWebSocket; // Guarded by this. private boolean executed; RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); } public Request request() { return originalRequest; } // 同步执行的实现 public Response execute() throws IOException { // 一个call只能执行一次 synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); try { // 将请求放在,请求池中执行,此处会立即执行 client.dispatcher().executed(this); // 获取结果,即执行多个链接器的调用链 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } } private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); } // 异步执行,不管行返回结果 public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); // AsyncCall是一个Runnable的实现类,同时一个是RealCall的内部类 client.dispatcher().enqueue(new AsyncCall(responseCallback)); } public void cancel() { retryAndFollowUpInterceptor.cancel(); } public synchronized boolean isExecuted() { return executed; } public boolean isCanceled() { return retryAndFollowUpInterceptor.isCanceled(); } "CloneDoesntCallSuperClone") // We are a final type & this saves clearing state. ( public RealCall clone() { return new RealCall(client, originalRequest, forWebSocket); } StreamAllocation streamAllocation() { return retryAndFollowUpInterceptor.streamAllocation(); } // 异步执行的线程封装,Android基本就是这里了 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; } 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); } } } /** * Returns a string that describes this call. Doesn't include a full URL as that might contain * sensitive information. */ String toLoggableString() { return (isCanceled() ? "canceled " : "") + (forWebSocket ? "web socket" : "call") + " to " + redactedUrl(); } String redactedUrl() { return originalRequest.url().redact(); } // 最重要的入口了 // 最重要的入口了 // 最重要的入口了 // 重要事情说三遍 Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List |
看来上面的代码,是不是被人家的想法折服。更精妙的还在后面呢,不要急。到此,一个请求已经完成,发送和接收,(不关心内部实现的话)。接下来我们再来看看,连接器是如何工作的。
Interceptor是一个接口,主要是对请求和响应的处理,而实现拦截器调用链的是其内部接口Chain
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public interface Interceptor { // 管拦截 Response intercept(Chain chain) throws IOException; interface Chain { Request request(); // 管分发,前行 Response proceed(Request request) throws IOException; Connection connection(); } } |
Interceptor.Chain的实现类只有一个RealInterceptorChain,也是处理调用过程的实现,其内部有个List装载了所有拦截器,大家想必也猜到了,对,就是迭代,当然也不是简简单单的接待了事。让我们看看源码实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// RealCall.getResponseWithInterceptorChain()中创建了一个实例 public final class RealInterceptorChain implements Interceptor.Chain { // RealCall.getResponseWithInterceptorChain()中已经赋值 private final Request request; private final List |
看了上面的代码是不是还不明白,到底怎么实现的,实际上就是迭代+递归。
每一个RealInterceptorChain会对应一个Interceptor,然后Interceptor在产生下一个RealInterceptorChain,知道List迭代完成。
Okhttp3的调用流程基本原理就是这样,重要的是思想,整个流程一气呵成,完全解耦。