本文地址:https://blog.csdn.net/qq_40785165/article/details/114766240,转载需附上此地址
大家好,我是小黑,一个还没秃头的程序员~~~
路是走出来的,而不是空想出来的。
相信大家找工作的时候都会被问及到Okhttp的原理以及源码分析,好记性不如烂笔头,所以这次我打算把它记录下来方便日后复习查看,也和大家分享一下,如果有什么不对之处还请大家多多指教!
这次的分析分为三个步骤:
- 网络请求发出去后到了哪里
- 请求是怎么被处理的
- 请求结束后又会做什么
(一)网络请求发出去后到了哪里
OkHttp发送请求有两种方式:enqueue/execute,在enqueue异步请求之前我们需要调用newCall(),newCall()返回的是RealCall对象
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
所以我们找到RealCall类中的enqueue()
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//最大并发请求数
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;
//消费者线程池
private ExecutorService executorService;
//等待中的请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
在Dispatcher类中,有两个构造函数,一个有传入线程池,一个没有传入线程池,没有传入线程池的话会在异步请求之前创建一个默认的线程池
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//创建线程池,SynchronousQueue为一个没有容量的队列
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;
}
前面讲到执行RealCall的enqueue()便会最终到Dispatcher的enqueue(),它的代码如下
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
(二)请求是怎么被处理的
@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);
}
}
上面的代码中,getResponseWithInterceptorChain()返回了response,并在相应的回调中返回,这是处理请求的地方,这里会添加一个拦截器链,如是否重定向,缓存拦截器,自定义拦截器等,代码如下:
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 (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//最后一个拦截器,会对服务器进行网络调用,在intercept()方法中构建头部以及body,并获取返回
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
接下来我们看代码最后面的proceed()方法,这个方法是RealInterceptorChain这个类实现的,代码如下:
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
我们接着点进去 ,在这里面会去做关于response的返回,在这里从拦截器列表中取出拦截器,并使用通过各个拦截器通过intercept()方法的实现来获取拦截器的调用返回,拦截器是按顺序取出来处理的,代码如下:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
return response;
}
到这里,问题二已解决了,请求是在getResponseWithInterceptorChain()获取返回的。
(三)请求结束后又会做什么
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();
}
}
关键在于promoteCalls()方法,代码如下:
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // 运行中的请求以及到了最大的请求数
if (readyAsyncCalls.isEmpty()) return; // 没有等待中的请求了
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.
}
}
从代码中可以看出,在一个请求结束后,会去对运行中的请求以及等待中的请求数进行判断,并将等待队列中的请求移除一个并添加到线程池中进行处理,即进入运行队列中处理,这就是请求结束后的内容了,到此为止,OkHttp源码分析的三个步骤就介绍完毕,日后我会接着分享自己在阅读源码的体会与总结,最后,希望喜欢我文章的朋友们可以帮忙点赞、收藏、评论,也可以关注一下,如果有问题可以在评论区提出,谢谢大家的支持与阅读!