先从最简单的例子入手分析
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url(api).get().build();
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
}
@Override public void onResponse(Call call, Response response) {
}
});
1.首先构建了OkHttpClient对象(实际开发中会使用单例模式来构建获取OkHttpClient);
2.接着构建Request请求对象,这里封装了最基本的接口地址和请求方式;
3.最后传入回调方法并发起接口请求。
下面逐步分析每个步骤
一.构建OkHttpClient
···
//拦截器
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
···
public Builder() {
dispatcher = new Dispatcher(); //请求任务调度器
protocols = DEFAULT_PROTOCOLS; //h2、http/1.1协议
connectionSpecs = DEFAULT_CONNECTION_SPECS; //不同版本TLS相关配置
eventListenerFactory = EventListener.factory(EventListener.NONE); //okhttp发起请求过程中会回调的监听器
proxySelector = ProxySelector.getDefault(); //代理服务器选择器
cookieJar = CookieJar.NO_COOKIES; //管理HTTP cookies的工具接口
socketFactory = SocketFactory.getDefault(); //创建socket,同时做一些扩展
hostnameVerifier = OkHostnameVerifier.INSTANCE; //校验证书的工具类
certificatePinner = CertificatePinner.DEFAULT; //管理信任证书的工具类
proxyAuthenticator = Authenticator.NONE; //代理证书
authenticator = Authenticator.NONE; //证书
connectionPool = new ConnectionPool(); //连接池复用
dns = Dns.SYSTEM; //DNS解析工具接口,对InetAddress.getAllByName(hostname)做了一次封装
followSslRedirects = true; //允许重定向
followRedirects = true; //允许重定向
retryOnConnectionFailure = true; //允许失败重试
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
以上是OkHttpClient构建时的默认配置,从这里就可以看出okhttp做了很多封装和优化,包括请求任务队列、协议兼容、SSL、连接池复用、重定向、重连机制、拦截器机制等。
二.创建Request
通过url方法将传入的接口地址拆解,用HttpUrl对象保存,拆解的组成部分有scheme、host、path、query等
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
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);
}
// 解析url
HttpUrl parsed = HttpUrl.parse(url);
if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
return url(parsed);
}
设置GET请求方式,同理还有POST方法
public Builder get() {
return method("GET", null);
}
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder method(String method, @Nullable RequestBody body) {
if (method == null) throw new NullPointerException("method == null");
if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must not have a request body.");
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must have a request body.");
}
this.method = method; // 赋值请求方式
this.body = body; // 保存请求体(get请求没有请求体)
return this;
}
这里使用最基本的配置创建Request对象,其中保存了url、headers、method、body等参数。还有一个tag参数,取消请求的时候会用到该参数。
三.发起请求
1.首先调用OkHttpClient的newCall方法创建RealCall对象,后续由该对象调用相关请求方法
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client; // 保存okHttpClient引用
this.originalRequest = originalRequest; // 保存request
this.forWebSocket = forWebSocket; // forWebSocket默认为false
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); // 创建重试和重定向拦截器
}
RealCall实现了Call接口的方法:
- Request request(); 返回保存的Request对象
- Response execute() throws IOException; 执行同步请求
- void enqueue(Callback responseCallback); 加入任务队列执行异步请求
- void cancel(); 取消未完成的请求
- boolean isExecuted(); 判断是否已执行execute/enqueue,一个call只能执行发起一次
- boolean isCanceled(); 判断是否已取消,即知否执行了cancel
- Call clone(); 复制一个一样的call,可以执行execute/enqueue无论原来的call是否已执行
2.创建完RealCall后,调用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)); // 加入到任务队列,通过Dispatcher对象分发事件
}
这里先创建AsyncCall将responseCallback包装进去,AsyncCall继承自NamedRunnable,在NamedRunnable的run方法中又调用了AsyncCall的execute方法。
加入任务的就是AsyncCall对象,Dispatcher内部通过三个双端队列来保存请求:
Deque<RealCall> runningSyncCalls; //保存正在执行的同步请求的RealCall
Deque<AsyncCall> readyAsyncCalls; //保存异步请求的AsyncCall(等待执行)
Deque<AsyncCall> runningAsyncCalls; //保存异步请求的AsyncCall(正在执行),该队列限制了总请求数不能超过64个且每个host下的请求数不超过5个
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//未超出容量,加入running队列,用线程池取线程去执行
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
//否则加入ready队列
readyAsyncCalls.add(call);
}
}
如果执行,则调用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); // 请求完成,从队列清除任务,并触发后续操作
}
}
}
3.请求完成调用Dispatcher的finished方法
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) { // 异步请求完成
finished(runningAsyncCalls, call, true);
}
/** Used by {@code Call#execute} to signal completion. */
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(); // 异步请求完成的为true
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run(); // 当前在请求中的任务为0(包括异步和同步),且设置了idleCallback(通过setIdleCallback方法设置),则触发idleCallback
}
}
此时为异步请求,会调用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();
// 如果满足同个host下的请求任务小于5个,则将它从readyAsyncCalls移至runningAsyncCalls,然后执行请求任务
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
// 再对runningAsyncCalls做一次检查
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
以上是okhttp发起网络请求的大致流程,先简单分析到这里,改天继续研究getResponseWithInterceptorChain()中的拦截器机制的实现。