国庆期间,没怎么出去玩,就宅在家里面学习,所以就来研究了一下okhttp的源码。okhttp的github地址:https://github.com/square/okhttp
简单使用
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
Call call = okHttpClient.newCall(request);
//同步请求
try {
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {}
@Override
public void onResponse(Call call, Response response) throws IOException {}
});
它的用法也是比较简单,前三步中异步跟同步的操作基本是一样的,就是最后稍有不同,好,我们现在就来逐一进行解析。
源码解析
首先我们来看看OkHttpClient实例的创建
OkHttpClient okHttpClient = new OkHttpClient.Builder().build()
它首先是通过一个构建者模式来创建它的一个实例。
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
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;
pingInterval = 0;
}
而Builder类是OkHttpClient的一个内部类,通过调用它的build方法就会把OkHttpClient的实例创建出来
public OkHttpClient build() {
return new OkHttpClient(this);
}
把OkHttpClient实例创建出来之后,接着就是Request的创建。其实它的创建跟OkHttpClient的创建大同小异,也是通过builder构建者模式创建的,不过有一点需要注意:
它默认的请求方法是get。
Call call = okHttpClient.newCall(request);
这个Call其实只是一个接口,因此不能直接创建它的实例,只能是去创建它的子类。
public interface Call extends Cloneable {
/** Returns the original request that initiated this call. */
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
这里它是利用我们刚刚创建好的okHttpClient实例的newCall方法进行创建,好我们就走进去看看:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
我们发现它这里是通过RealCall的newRealCall方法去创建的,我们继续往里面看:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
这里我们主要看第一行,直接就是创建了RealCall的实例,而这个RealCall也是实现了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、Request的实例,还有就是创建了RetryAndFollowUpInterceptor这个拦截器类,拦截器在后面会有讲解,这是非常重要的一点。
因为同步和异步的前三步都是一样的,那我们现在来看看最后一步大家有什么区别。
1. 同步
同步的话就会去调用Call的execute方法,从上面的讲解也知道Call是一个接口,所以调用的是它的实现类RealCall。
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
这里首先就会去判断executed这个标志位是否为true,因为同一个请求只能是请求一次。
接下去往下看这句client.dispatcher().executed(this)。
这里会调用client.dispatcher的exceuted方法。而client的dispatcher方法获取的就是Dispatcher这个实例,这个类的实例是在构建OkHttpClient的时候创建的。Dispatcher这个类是很重要的一个类,它维护请求的状态(同步还是异步),并且维护一个线程池,用于执行请求,这从后面可以知道。那我们现在看看它的executed方法:
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
这里出现了一个runningSyncCalls这个变量,究竟是什么呢?我们看看它的定义,也是在Dispatcher这个类里面:
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
其实它就是一个队列,当有同步请求的时候,就会把这个Call添加到一个同步队列中去。
回到RealCall的executed方法中去,把RealCall添加到同步队列之后,就会去调用getResponseWithInterceptorChain()这个方法获取Response,这个方法可以说是整个OkHttp最重要的部分,拦截器链,这里我们留到下一章节来说。现在我们来看看finally那部分:
client.dispatcher().finished(this);
这里会调用Dispatcher的finish方法,里面做了什么,我们进去看看:
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();
}
}
它这里会把同步队列runningSyncCalls和当前的Call作为参数传到finished的重载方法中。在这个重载方法里面可以看到,它会把这个同步的Call从队列中移除。因为传进来的promoteCalls是为false,所以promoteCalls这个方法就不会执行,接下来就会调用runningCallsCount()这个方法,从名字上我们可以猜测它应该是统计Call的数量:
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
它是在统计两个队列的数量,runningAsyncCalls是接下来会讲解到运行中的异步队列。这样同步的讲解完了,接下来就要看看异步的了。
2. 异步
异步调用的是Call的enqueue方法,我们进去看看:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
同样的,我们只需要看最后一行,它首先new了一个AsyncCall实例,我们看看它的定义
final class AsyncCall extends NamedRunnable
它是RealCall里面的一个内部类,而它又继承了一个NamedRunnable,我们又继续看看这个NameRunnable:
public abstract class NamedRunnable implements Runnable
现在终于明白了,原来这个AsyncCall就是一个Runnable线程。好我们看回Dispatcher的enqueue的这个方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
这里有几个变量,我们先来看看它的定义:
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** 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<>();
这几个都是Dispatcher的成员变量
maxRequests:最大可执行的线程数
maxRequestsPerHost:最大的主机数
readyAsyncCalls:异步的就绪队列
runningAsyncCalls:异步的执行队列
回到enqueue方法,若条件不符合的时候,就会把Call添加到异步的就绪队列中等待;若条件成立的话就会把Call添加到执行队列,然后调用executorService().execute(call)。这里出现了一个executorService()方法,我们看看:
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
这里会返回一个线程池,在Dispatcher类中也是维护了一个自己的线程池来执行AsyncCall。那我们来看看AsyncCall的run方法,但是AsyncCall里面并没有run方法,而它的run方法是在它的父类NamedRunnable中,而最终也是会调用execute方法,所以我们看看AsyncCall的execute方法:
@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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
同样的,这里会调用getResponseWithInterceptorChain()这个方法获取Response,后面会讲到,然后就处理回调消息。同样的我们也要看看finally里面的finished方法。
/** Used by {@code AsyncCall#run} to signal completion. */
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方法差不多,其中的一个区别就是promoteCalls是为true的,所以就会去调用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.
}
}
这里首先会判断正在运行的异步队列数量有没有超过最大限值,然后就是遍历这个异步的就绪队列,把就绪队列中的AsyncCall添加到执行队列中,并且放到线程池中执行。
下一节就会去讲解这个拦截器链,OkHttp源码解析(二),谢谢!