Okhttp 源码流程梳理

这是对okhttp源码流程的一个梳理,是本人的个人理解。如果有误,可以指出。文中引用的图片是引用网上的图。文章本意是将大概逻辑梳理下,便于查看源码。

  • okhttp网络请求步骤

1.创建okhttpClient
OkhttpClient okhttpClient = new OkhttpClient.builder().readTimeout(5000, TimeUnit.MILLISECONDS)…build(); 使用到了build建造模式

2创建Request对象 请求报文
Request request = new Request.builder().url().post()….build();使用到了build建造模式

3.Call对象的创建。
Call call = okhttpClient.newCall(request);
4.
同步请求:发送完请求后,会阻塞当前线程。直到收到服务器的响应。
call.execute();

异步请求:onResponse和onFailure方法都发生在工作线程(子线程)
call.enqueue(new CallBack{});

  • 源码流程解析

当我们用OkHttpClient.newCall(request)进行execute/enenqueue时,实际是将请求Call放到了Dispatcher中,okhttp使用Dispatcher进行线程分发,它有两种方法,一个execute()方法,是同步方法,另一种是异步方法,enqueue().
1.同步方法即一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过同步方法不能在Android的主线程中执行, 否则会报错;
execute()方法,首先判断是否已执行过,如果已经执行过,则抛出异常信息,也就是说一次Call实例只能调用一次execute()方法,
接着调用getResponseWithInterceptorChain()方法返回Response对象,
最后finally中,调用Dispatcher的finished()方法,再从已经执行的runningSyncCalls中移除本次Call。如果未执行,则调用Dispatcher类的executed()方法将该Call加入到runningSyncCalls队列中,
2.异步方法,和同步方法一样,首先都校验这个Call是否已经被执行,如果执行过,就报异常。如果未执行,则调用Dispatcher分发器的enqueue()方法使用了队列进行并发任务的分发(Dispatch)与回调,如果runningAsyncCalls的大小小于最大请求数量(最大线程数量、并发数量)并且call小于最大主机请求限制,那么将call 加入到runningAsyncCalls中,接着线程池执行call;否则,将call加入到readyAsyncCalls(异步调用准备任务)。
接着调用getResponseWithInterceptorChain()方法返回Response对象,
最后finally中,调用Dispatcher的finished()方法,finished()方法先从runningAsyncCalls(异步请求队列)删除已经执行的异步请求,然后接着调用了promoteCalls()方法,主要就是遍历等待队列,并且需要满足同一主机的请求小于maxRequestsPerHost时,循环readyAsyncCalls(异步调用准备任务),将call加入到runningAsyncCalls(异步请求队列)中,并在readyAsyncCalls(异步调用准备任务)删除掉该call,接着线程池执行call。

Dispatcher维护了如下变量,用于控制并发的请求

public final class Dispatcher {
  /** 最大并发请求数为64 */
  private int maxRequests = 64;
  /** 每个主机最大请求数为5 */
  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<>();

getResponseWithInterceptorChain()内部添加各种拦截器,利用RealInterceptorChain将已有的拦截器进行串联,通过最后一个拦截器CallServerInterceptor对服务器进行网络调用,
各个拦截器的作用如下:
RetryAndFollowUpInterceptor:在连接失败后进行重新连接,必要时进行重定向,如果调用被取消,可能会抛出IOException。最大重连次数20
BridgeInterceptor:构建访问网络的桥梁,首先,将用户请求转换成网络请求,然后访问网络,最后将网络响应转换成用户响应。
CacheInterceptor:缓存拦截器,从缓存中获取服务器请求,或者把服务器响应写入缓存中。
ConnectInterceptor:打开一个连接,去连接目标服务器。
CallServerInterceptor:拦截器链中的最后一个链点,通过网络请求服务器。
流程图
这里写图片描述
最后上一个完整的流程图
这里写图片描述

猜你喜欢

转载自blog.csdn.net/csdn_mm/article/details/80508217