前面两篇文章,我们介绍了OKHttp的基本用法,今天这篇文章将从OkHttp源码的角度来分析OkHttp的整个工作流程。
初始化一个OkHttpClient对象,
OkHttpClient mOkHttpClient = new OkHttpClient();
OkHttpClient的构造函数中又初始化了一个Builder对象,
public OkHttpClient() {
this(new Builder());
}
Builder的构造函数中,默认会创建对象以及一些属性,Builder对象是用来构造网络请求的。这种设计模式和Android的对话框中的Builder几乎是一个意思。
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
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;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
接着,创建一个请求,
Request request = new Request.Builder()
.url(url)
.build();
Request类是HTTP请求,它携带了请求地址、请求方法、请求头部、请求体以及其他信息。它也是通过Builder模式创建的。Request.Builder().build()源码,
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
Request的构造方法,
private Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
发起请求有两种方式,一种是同步,一种是异步,下面分别看看如何实现,
同步请求,
Response response = mOkHttpClient.newCall(request).execute();
Response是HTTP响应,它继承自Closeable(Closeable继承自AutoCloseable,AutoCloseable资源自动关闭的接口),它携带了请求、网络请求协议、返回状态码、请求头、响应体等等,其中,网络请求协议是Protocol,Protocol是一个枚举类型,包含4中类型,
public enum Protocol {
/**
* An obsolete plaintext framing that does not use persistent sockets by default.
*/
HTTP_1_0("http/1.0"),
/**
* A plaintext framing that includes persistent connections.
*
* <p>This version of OkHttp implements <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC
* 2616</a>, and tracks revisions to that spec.
*/
HTTP_1_1("http/1.1"),
/**
* Chromium's binary-framed protocol that includes header compression, multiplexing multiple
* requests on the same socket, and server-push. HTTP/1.1 semantics are layered on SPDY/3.
*
* <p>This version of OkHttp implements SPDY 3 <a
* href="http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">draft 3.1</a>. Future
* releases of OkHttp may use this identifier for a newer draft of the SPDY spec.
*/
SPDY_3("spdy/3.1"),
/**
* The IETF's binary-framed protocol that includes header compression, multiplexing multiple
* requests on the same socket, and server-push. HTTP/1.1 semantics are layered on HTTP/2.
*
* <p>HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support {@linkplain
* CipherSuite#TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} , present in Java 8+ and Android 5+. Servers
* that enforce this may send an exception message including the string {@code
* INADEQUATE_SECURITY}.
*/
HTTP_2("h2");
}
接着看
OkHttpClient.newCall(request);
Call类是一个准备执行的请求,它可以被取消,它代表着一个单一的请求/响应流,不能被执行两次。Call类是一个接口,
public interface Call {
/** Returns the original request that initiated this call. */
Request request();
/**
* Invokes the request immediately, and blocks until the response can be processed or is in
* error.
*
* <p>The caller may read the response body with the response's {@link Response#body} method. To
* avoid leaking resources callers must {@linkplain ResponseBody close the response body}.
*
* <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
* not necessarily indicate application-layer success: {@code response} may still indicate an
* unhappy HTTP response code like 404 or 500.
*
* @throws IOException if the request could not be executed due to cancellation, a connectivity
* problem or timeout. Because networks can fail during an exchange, it is possible that the
* remote server accepted the request before the failure.
* @throws IllegalStateException when the call has already been executed.
*/
Response execute() throws IOException;
/**
* Schedules the request to be executed at some point in the future.
*
* <p>The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually
* immediately unless there are several other requests currently being executed.
*
* <p>This client will later call back {@code responseCallback} with either an HTTP response or a
* failure exception.
*
* @throws IllegalStateException when the call has already been executed.
*/
void enqueue(Callback responseCallback);
/** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
void cancel();
/**
* Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
* #enqueue(Callback) enqueued}. It is an error to execute a call more than once.
*/
boolean isExecuted();
boolean isCanceled();
interface Factory {
Call newCall(Request request);
}
}
newCall()方法是创建一个Call对象,
@Override
public Call newCall(Request request) {
return new RealCall(this, request);
}
RealCall类实现了Call类,下面展示RealCall()方法的代码,
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
接着是RealCall的execute()方法。execute()方法是同步方法,即一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过同步方法不能在Android的主线程中执行, 否则会报错。
OKHttp提供了execute()方法(同步方法)和enqueue()方法(异步方法),下面我们先看看execute()方法(同步方法),
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
execute()方法,首先判断是否已执行过,如果已经执行过,则抛出异常信息,也就是说一次Call实例只能调用一次execute()方法,和我们之前说的一样。
如果未执行,则调用Dispatcher类的executed()方法将该Call加入到一个双端队列中,
...
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//双端队列
...
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
接着调用getResponseWithInterceptorChain()方法返回Response对象,最后finally中,调用Dispatcher的finished()方法,在从已经执行的双端队列中移除本次Call。
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
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();
}
}
通过上面分析,真正发出网络请求,返回结果应该是getResponseWithInterceptorChain()方法,那么接下来,主要看看这个方法
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
仔细查看便会发现,该方法是组装各种拦截器为一个拦截器链,最后调用RealInterceptorChain的proceed()方法,来处理这个请求,
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpStream, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpStream != null && !sameConnection(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpStream != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpStream != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
拦截器Interceptor和拦截器链Chain都是接口,
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
下面用一张流程图来说明拦截器链递归从拦截器中返回Response(这个过程很类似Android中的事件处理机制)
下面再看看enqueue()方法(异步方法),指在另外的工作线程中执行http请求, 请求时不会阻塞当前的线程, 所以可以在Android主线程中使用。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
该方法和同步方法一样,首先都校验这个Call是否已经被执行,如果执行过,就报异常。如果为执行,则调用Dispatcher分发器的enqueue()方法。首先,我们看看AsyncCall这个类,
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl().toString());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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);
}
}
}
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();
}
AsyncCall–实际上是一个Runnable,在run()方法中调用了execute()方法,在该方法中,我们又看到既熟悉又陌生的代码(getResponseWithInterceptorChain()),
Response response = getResponseWithInterceptorChain();
执行该方法后,根据响应结果设置回调方法的结果。AsyncCall执行完调用Dispatcher的finished(this)方法,
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();
}
}
finished()方法先从runningAsyncCalls(异步请求队列)删除已经执行的异步请求,然后接着调用了promoteCalls()方法,
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
首先判断runningAsyncCalls(异步请求队列)是否还有请求,如果有,则返回;否则readyAsyncCalls(异步调用准备任务)是否为空,如果为空,则返回;否则,循环readyAsyncCalls(异步调用准备任务),将call加入到runningAsyncCalls(异步请求队列)中,并在readyAsyncCalls(异步调用准备任务)删除掉该call,接着线程池执行call。
下面接着看Dispatcher分发器的enqueue()方法,
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
如果runningAsyncCalls的大小小于最大请求数量(最大线程数量、并发数量)并且call小于最大主机请求限制,那么将call 加入到runningAsyncCalls中,接着线程池执行call;否则,将call加入到readyAsyncCalls(异步调用准备任务)。
PS: runningCallsForHost()方法,循环判断cal的hostl和runningAsyncCalls的中的call的host相同的数量。同一请求是否超过想过请求同时存在的最大值。
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
可以看到请求的最核心代码,与Dispatcher类分不开,下面就看看Dispatcher类,Dispatcher是异步请求的策略,
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
private ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
...
}
Dispatcher维护了如下变量,
int maxRequests = 64: 最大并发请求数为64
int maxRequestsPerHost = 5: 每个主机最大请求数为5
Runnable idleCallback:Runnable对象,在删除任务时执行
ExecutorService executorService:消费者池(也就是线程池)
Deque<AsyncCall> readyAsyncCalls:缓存,异步调用准备执行任务
Deque<AsyncCall> runningAsyncCalls:正在运行的异步任务,包含取消尚未完成的调用
Deque<RealCall> runningSyncCalls: 正在运行的同步任务,包含取消尚未完成的调用
至此,OKHttp的源码分析就结束了!希望本篇文章对读者有所收获!
下面结合本篇文章,总结OKHttp的整体流程,流程图如下所示,