Android OKHttp源码解析

来源:互联网 发布:阿里云空间怎么买 编辑:程序博客网 时间:2024/06/01 07:27

学习了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请求最重要的的是拦截器的作用,下面再继续看看拦截器的具体内容。