OkHttp流程分析(1)

  • Call :发起我们的http请求

开始分析

OkHttpClient和Request

先看看我们的 OkHttpClient Request

OkHttpClient.java

public OkHttpClient() {
this(new Builder());
}

我们跟进代码可以看到OkHttpClient是一个构建者模式。Request不跟进也可以看到是一个构造者模式。

接下来,我们继续看Call

Call

//OkHttpClient.java
Call newCall(Request request) {
//此处传入我们的OkHttpClient
return RealCall.newRealCall(this, request, false);
}

//RealCall.java
RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
//Transmitter意为发射器,功能挺杂。注释说是OkHttp的应用程序和网络层之间的桥梁
call.transmitter = new Transmitter(client, call);
return call;
}

在这段代码中,我们可以看到我们得到的Call的实例是RealCall。所以我们enqueue()方法的调用实际是RealCall的方法。

@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException(“Already Executed”);
executed = true;
}
transmitter.callStart();
//从我们之前传入OkHttpClient中获取其中的Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

注意这里有一个Dispatcher。这个类负责我们网络请求的调度策略。在这段代码中我们用AsyncCall封装了我们的Callback。AsyncCall 是一个NamedRunnable。在这个NamedRunnable中封装了我们的execute()

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();
}

execute()的具体实现如下

@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//此处得到我们的需要的网络数据
Response response = getResponseWithInterceptorChain();
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);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}

在上面这个方法中我们可以看到请求的结果是如何获得,那么这个runnable任务是怎么调度执行的呢?我们就得回过头看看Dispatcher类的enqueue()方法做了啥

void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);

if (!call.get().forWebSocket) {
//如果有请求同一host的AsyncCall就进行复用
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
推动执行方法
promoteAndExecute();
}

private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));

List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//循环收集可以执行的AsyncCall
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();

if (runningAsyncCalls.size() >= maxRequests) break; // 最大执行的call大于64 跳出
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // 请求同一host的call > 5 跳过

i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}

//把可以执行的AsyncCall,统统执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//executorService()返回一个线程池
asyncCall.executeOn(executorService());
}

return isRunning;
}

void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//线程池运行Runnable,执行run,调用前面提到的AsyncCall.execute
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException(“executor rejected”);
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
//失败回调
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
//结束
client.dispatcher().finished(this);
}
}
}

到了这里我们的AsyncCall就顺利执行了。整个Okhttp代码的主干就在这里。接下来我们继续探讨okhttp这个框架的一些细节设计

拦截器链

前边得到Response的地方,我们调用了getResponseWithInterceptorChain()。但没细讲,这个部分就是大名鼎鼎的okhttp的拦截器链。

//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
List interceptors = new ArrayList<>();
//添加自定义拦截器
interceptors.addAll(client.interceptors());
//添加默认拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加自定义网络拦截器(在ConnectInterceptor后面,此时网络连接已准备好)
interceptors.addAll(client.networkInterceptors());

新的开始

改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。

《系列学习视频》

《系列学习文档》

《我的大厂面试之旅》

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值