Android OKHttp源码解析

学习了OKHttp的使用,现在来学学源码。

1、OkHttp是一个高效优秀的HTTP库
网上有很多相关的介绍文档 。

2、OKHttp的简单使用实例,实际一般都是和Retrofit结合使用,下面是OKHTTP的使用实例,分别就一二三四步进行分析:

(一) final OkHttpClient client = new OkHttpClient();

       okHttpClient = new OkHttpClient.Builder()
            .addInterceptor()
            .addNetworkInterceptor()
            .build();

(二)   Request request = new Request.Builder()
            .url("https://www.baidu.com/")
            .get()
            .build();

(三) Response response = client.newCall(request).execute();  //同步请求

(四)   okHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d(TAG,"e="+e);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
           Log.d(TAG,"response="+ response.body().toString());
        }
    });

OKHttp的调用流程图:
这是我画的一个粗略的流程图

下面来看看具体的过程:

一、OKHttpClient对象的创建

1 :创建默认设置的client,或者如上的创建:
public final OkHttpClient client = new OkHttpClient();

2: OKHttpClient通过Builder模式创建

 okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new HttpLogginInterceptor())
                 .cache(new Cache(cacheDir,cacheSize))
                 .build();

 OKHttpClient在一个应用程序中最好使用一个单例,因为每个OKHttpClient实例持有自己的线程池和连接池,重用线程池和连接池可以节省内存,如果每个请求都实例化一个client那么必然造成它本身线程池和连接池的资源浪费。当系统检测到她们已经闲置时,线程和连接资源会被自动释放,当然有需要时也可以主动释放。

  * 通过Builder方式构建的OKHttpClient实例可以共享连接池、线程池和配置

  * 通过client.dispatcher().executorService().shutdown():停止调度器的service,那么之后的请求都会被拒绝

  * 通过client.connectionPool().evictAll():清除连接池,但是守护进程可能并不会马上释放

  * 如果client有缓存的话,可以通过client.cache().close()来 关闭,但是不能重复调用,否则可能会crash

  * OKHttp使用了守护线程来维护HTTP/2的连接,闲置时则会自动的停止 

 */

 步骤1:new OKHttpClient:分析OKHttpClient的主体
 步骤2:Builder() :分析Builder的构建


 步骤1:

 OKHTTPClient的关键代码:  
 public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {

      //Protocol是一个定义了几种协议版本http1.0,http1.1,spdy3,http2的枚举,这里返回的是装载了两个枚举常量Protocol.HTTP_2和Protocol_的不可变list
      static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
      Protocol.HTTP_2, Protocol.HTTP_1_1);

      //ConnectionSpec:证书
      static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);

      /**
        * 静态Internal实例对象:
        * OKHttp3 内部一些更新的API,继承自OKHTTP的包也能够使用,这个Internal仅在OKHTTPClient中使用
        * 主要通过builder来设置到client中去 
        */
      static {
       Internal.instance = new Internal() {
      }
      }
  }

  //Dispatcher:执行异步请求的代理,下面有这个类的具体分析
  final Dispatcher dispatcher; 
  //网络代理,有Direct、HTTP、SOCKS三种
  final Proxy proxy;

  //连接规范,配置Socket连接层,对于HTTPS,还能配置安全传输层协议TLS版本与密码套件(CipherSuite)
  final List<ConnectionSpec> connectionSpecs;
  //Interceptor:拦截器,观察、修改已经发出的请求或得到响应。常用来添加、移除或者转换请求或者
  //response的header
  final List<Interceptor> interceptors;
  final List<Interceptor> networkInterceptors; 

  //EventListener:请求过程监听器
  final EventListener.Factory eventListenerFactory;  

  /**
    * CookieJar:管理cookie,根据URL保存或者取出cookie。
    * 可以自定义,有两个方法:
    * void saveFromResponse(HttpUrl url, List<Cookie> cookies);
    * List<Cookie> loadForRequest(HttpUrl url);
    */
  final CookieJar cookieJar;

  //Cache :缓存HTTP和HTTPS结果到文件系统,用常见的DiskLruCache来对response进行缓存。
  final Cache cache;

  //SocketFactory : 通过工厂方法创建Socket 
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;
  final CertificateChainCleaner certificateChainCleaner;

  //主机名验证器,与HTTPS中的SSL相关,当握手时如果URL的主机名不是可识别的主机,就会要求进行主机名验证
  /**
    *public interface HostnameVerifier {

     //通过session验证指定的主机名是否被允许
    boolean verify(String hostname, SSLSession session);
    }
   */
  final HostnameVerifier hostnameVerifier;

  //证书锁,约束哪些证书可以被信任,防止某些证书机构的攻击行为,如果所有证书都不被信任将抛出
  //SSLPeerUnverifiedException异常。

  final CertificatePinner certificatePinner;
  //授权
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  final ConnectionPool connectionPool;
  //DNS域名转换
  final Dns dns;


 }

步骤2;Builder()的创建相关代码:


    public Builder() {
      dispatcher = new Dispatcher(); //实例线程调度器
      protocols = DEFAULT_PROTOCOLS;   
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();   //获取系统的DefaultProxySelector
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();

      connectionPool = new ConnectionPool();  //实例化一个连接池

      //设置默认的连接时间,读写时间
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;

    }
通过.build()生成OKHTTPClient实例,.将Builder设置的参数设置给OKHTTPClient。

Dispatcher:

/**
  * Dispatcher:是异步请求时的代理,所有请求都是在这里进行调用以及处理
  * 每个Dispatcher使用一个ExecutorService来调用call请求。
  * 如果 提供了自定义的executor,需要支持获取最大的请求数,因为Dispatcher需要根据最大值来维护请求队列
  */
public final class Dispatcher {

  //默认的最大请求并发数64    
  private int maxRequests = 64;  

  //每个主机最大的请求数
  private int maxRequestsPerHost = 5;

  //当正在运行的请求数目为0时的回调
  private Runnable idleCallback;

  //线程池
  private ExecutorService executorService;

  //已ready的异步请求队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  //正在运行的异步请求队列,包括已经cancel但是还没有finish
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  //正在运行的同步请求队列,包括cancel但没有finish的
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();


  //可传入自定义的线程池
  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

  //创建一个线程池实例对象
  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;
  }

  //设置最大的可同时发生的请求数目,如果超过这个请求数,那么就等待正在运行的完成之后再调用
  public synchronized void setMaxRequests(int maxRequests) {
    if (maxRequests < 1) {
      throw new IllegalArgumentException("max < 1: " + maxRequests);
    }
    this.maxRequests = maxRequests;

    //将请求放入正在运行队列中
    promoteCalls();
  }

  public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
    if (maxRequestsPerHost < 1) {
      throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
    }
    this.maxRequestsPerHost = maxRequestsPerHost;
    promoteCalls();
  }


  //异步请求添加:如果此时运行队列大小小于最大值并且共享主机数小于最大值,则添加到正在运行队列并且将请求放入线程池执行,否则只是添加到准备队列中
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

  //取消所有的请求
  public synchronized void cancelAll() {
    for (AsyncCall call : readyAsyncCalls) {
      call.get().cancel();
    }

    for (AsyncCall call : runningAsyncCalls) {
      call.get().cancel();
    }

    for (RealCall call : runningSyncCalls) {
      call.cancel();
    }
  }

  //异步请求被调用的过程
  private void promoteCalls() {

    //1、首先判断此刻运行的Call数目是否>=最大的请求数,或者没有正在等待的请求,则不需要再加载新的请求
    if (runningAsyncCalls.size() >= maxRequests) return; 
    if (readyAsyncCalls.isEmpty()) return


    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      /**
        * 2、遍历即将运行的的Call,将其的host和正在运行的队列的host比较,如果共享主机数小于最大值的话
        * 则将该请求添加到正在运行队列,并且从准备队列中移除
        * 将该请求放入线程池执行
        * 否则就继续等待。 
        * 
        */
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      //添加的call超过了最大的值,则停止增加新的请求。
      if (runningAsyncCalls.size() >= maxRequests) return; 
    }
  }

  //返回共享主机的请求数目
  private int runningCallsForHost(AsyncCall call) {
    int result = 0;
    for (AsyncCall c : runningAsyncCalls) {
      if (c.host().equals(call.host())) result++;
    }
    return result;
  }

  //添加同步请求到运行队列中
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }


  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  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) {
      //将该请求call从相应的队列移除        
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");

      //移除之后再从准备队列往运行队列中添加新的请求【异步请求】
      if (promoteCalls) promoteCalls();

      runningCallsCount = runningCallsCount();

      idleCallback = this.idleCallback;
    }

    //如果运行数目为0并且回调不为空,则调用回调的方法通知接收者请求已完成
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

 //获取ready状态中的异步请求队列
  public synchronized List<Call> queuedCalls() {
    List<Call> result = new ArrayList<>();
    for (AsyncCall asyncCall : readyAsyncCalls) {
      result.add(asyncCall.get());
    }
    return Collections.unmodifiableList(result);
  }

  //返回running状态中的异步请求队列
  public synchronized List<Call> runningCalls() {
    List<Call> result = new ArrayList<>();
    result.addAll(runningSyncCalls);
    for (AsyncCall asyncCall : runningAsyncCalls) {
      result.add(asyncCall.get());
    }
    return Collections.unmodifiableList(result);
  }

  //返回ready状态的异步请求数目,同步请求是马上执行的,所以没有ready这一状态
  public synchronized int queuedCallsCount() {
    return readyAsyncCalls.size();
  }
   //返回running状态的请求数目
  public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }
}

二、创建一个网络请求对象Request

Request request = new Request.Builder()
        .url("https://www.baidu.com/")
        .get()
        .build();   

来看看Request的关键代码,Request同样通过Builder模式进行创建。

//Request是请求的实体,封装了请求的URL地址、请求方法,请求头、请求参数、请求体、请求响应体等等,
  public final class Request {
    //HttpUrl封装了请求url\post等相关信息
  final HttpUrl url;
   //OKHttp支持主流的网络请求,get/post/delete/put等方法 
  final String method;
  //定义请求头
  final Headers headers;
  //请求体
  final RequestBody body;


  private volatile CacheControl cacheControl;

  /**
   * 返回该响应的缓存控制指令,不为空,即使该响应没有包含Cache-Control * *头,、CacheControl是从响应header解析出来的缓存控制指令。
   */
  public CacheControl cacheControl() {
    CacheControl result = cacheControl;
    return result != null ? result : (cacheControl = CacheControl.parse(headers));
  }

  //判断是否是HTTPS
  public boolean isHttps() {
    return url.isHttps();
  }

  public static class Builder {
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;  //put 或 post、patch时定义的请求体
    Object tag;

    public Builder() {
      this.method = "GET"; //默认为GET方法
      this.headers = new Headers.Builder();
    }

    //设置当前请求为下列的某种请求
    public Builder get() {
      return method("GET", null);
    }

    public Builder head() {
      return method("HEAD", null);
    }

    public Builder post(RequestBody body) {
      return method("POST", body);
    }

    public Builder delete(RequestBody body) {
      return method("DELETE", body);
    }

    public Builder delete() {
      return delete(Util.EMPTY_REQUEST);
    }

    public Builder put(RequestBody body) {
      return method("PUT", body);
    }

    public Builder patch(RequestBody body) {
      return method("PATCH", body);
    }
    //拓展方法,可定义任意的请求方法,以及请求体 
    public Builder method(String method, 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;
      return this;
    }
  }
}

三、通过OKHTTPClient来发起请求

先来看看同步请求:
 Response response =  okHttpClient.newCall(request).execute();

 步骤1:看看okHttpClient.newCall(request)做了什么

//1:生成一个RealCall对象
@Override public Call newCall(Request request) {
  return new RealCall(this, request, false );
}

//2:RealCall对象的关键代码
//RealCall实现了Call,Call是一个定义请求的方法的接口,Request定义了请求的基本属性、设置,Call定义了请求的操作,同步、异步、取消等各项操作

  final class RealCall implements Call {  

  final OkHttpClient client; 
  //失败重连拦截器,在下面有介绍
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
  //事件监听器,监听请求的步骤,用工厂模式创建实例对象
  final EventListener eventListener;
  //请求对象
  final Request originalRequest;

  // Guarded by this.
  private boolean executed;

  //创建RealCall的实例对象
  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    this.eventListener = eventListenerFactory.create(this);
  }

   步骤2:调用realCall.execute()方法执行请求,下面详细看看这个方法做了什么操作

  @Override public Response execute() throws IOException {
    synchronized (this) {
    //  执行标志,不能重复执行
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

    try {
      //前面有看到,请求是由Dispatcher来调度的,所以RealCall的execute()进入到Dispatcher的executed()方法中
      client.dispatcher().executed(this);
      //如何获取请求的返回结果的,可以看到最终的网络请求其实就是在这里做的。
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }


  看看getResponseWithInterceptorChain()具体的实现:

   Response getResponseWithInterceptorChain() throws IOException {

    //看到这里添加了一系列的拦截器给interceptors,一个个看看这些拦截器都是做什么的   

    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());

    //retryAndFollowUpInterceptor:失败重连重定向拦截器
    interceptors.add(retryAndFollowUpInterceptor);

    //BridgeInterceptor:从应用程序代码到网络代码的桥梁,将用户的request转化成网络请求,然后根据网络响应转化为用户的response。
    interceptors.add(new BridgeInterceptor(client.cookieJar()));

    //CacheInterceptor:从缓存中发起request,并将响应写入的缓存中
    interceptors.add(new CacheInterceptor(client.internalCache()));

    //ConnectInterceptor:打开连接到指定服务器的连接,并且传递给下一个拦截器
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }

    //CallServerInterceptor:这是拦截器链中的最后一个拦截器,它用于对服务器发起网络请求
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //最后将所有的拦截器传递给RealInterceptorChain对象,执行proceed()操作
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

可以看出这是一种责任链的模式,每一个拦截器负责一项功能,完成之后往下传递。

//看看chain.proceed()做的具体内容,为了更加简明起见,把异常处理去掉

 @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {

    //index是传给RealInterceptorChain的拦截器链的索引
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    //调用RealInterceptorChain中的下一个拦截器
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);

    //获取当前索引的拦截器        
    Interceptor interceptor = interceptors.get(index);

    //执行拦截器的intercept的方法,最终得到返回结果response,返回给RealCall。
    Response response = interceptor.intercept(next);

    return response;
  }

以上是OKHttp请求调用的基本流程。OKHttp请求最重要的的是拦截器的作用,下面再继续看看拦截器的具体内容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值