OkHttp网络请求原理流程解析

1.OkHttpClient
OkHttpClient.Builder()使用builder模式,用户可以自定义相应的参数
相关可以配置的和Client相关的还有

 private static final List DEFAULT_PROTOCOLS = Util.immutableList(
      Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1);
    //默认支持的协议
  private static final List DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT);
  //使用https的版本和密码套件
  final Dispatcher dispatcher;//调度,异步请求
  final Proxy proxy;//代理 java.net
  final List protocols;
  final List connectionSpecs;
  final List interceptors;//拦截器
  final List networkInterceptors;//网络拦截器
  final ProxySelector proxySelector;//代理选择器
  final CookieJar cookieJar;//http cookies 管理方案和 持久化
  final Cache cache;//缓存
  final InternalCache internalCache;//内部缓存
  final SocketFactory socketFactory;//socket 工厂 java.net
  final SSLSocketFactory sslSocketFactory; //SSLSocket 工厂 java.net.ssl 
  final CertificateChainCleaner certificateChainCleaner;//证书方案
  final HostnameVerifier hostnameVerifier;//hostName 校验 OkHostnameVerifier
  final CertificatePinner certificatePinner;//固定的证书
  final Authenticator proxyAuthenticator;//代理的身份认证
  final Authenticator authenticator;// web的身份认证
  final ConnectionPool connectionPool;//连接池
  final Dns dns;//DNS
  final boolean followSslRedirects;//是否 执行 ssl redirect
  final boolean followRedirects;//是否执行 redirect
  final boolean retryOnConnectionFailure; //连接失败后是否重试
  final int connectTimeout;//连接超时时间
  final int readTimeout;// 读取超时
  final int writeTimeout;// 写入超时

开发一般会用到的是

 .connectTimeout(30, TimeUnit.SECONDS)
  .writeTimeout(30, TimeUnit.SECONDS)
  .readTimeout(30, TimeUnit.SECONDS)
  .addInterceptor(interceptorImpl)

连接时间,写时间,读时间以及对应的Interceptor相关的拦截器
2.构建Request
Request用的也是Builder模式,好处主要是可以动态配置相应的参数

Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }

tag主要是做标识的,请求返回为null时候的标识操作
3.构建Call
构建Call,主要是调用RealCall.newRealCall方法,并在其内部添加了一个事件回调监听

/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
  
  //RealCall
  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    //添加一个事件回调,后续会有用处
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

而在newRealCall方法中同时也调用了RealCall的构造方法
构造方法中加入了RetryAndFollowUpInterceptor重试拦截器,okhttp中加入了很多拦截器,这也是一大特色

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

4.执行异步请求enqueue

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

executed以及synchronized主要是用来防止重复操作和多线程同步用的

接下来的方法

private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

重试监听器做一些栈StackTrace记录,以及eventListener.callStart(this);事件监听做回调处理,不影响流程

接着就到了Dispatcher的enqueue方法

 /** Ready async calls in the order they'll be run. */
  private final Deque readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque runningSyncCalls = new ArrayDeque<>();

 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

Dispatcher中定义三个队列分别是readyAsyncCalls异步等待,同步运行runningAsyncCalls以及runningSyncCalls异步运行队列,enqueue方法中,当运行异步队列个数小于最大请求数(64)并且同一Host请求个数小于maxRequestsPerHost(5)则加入异步运行队列,并且用线程执行,否则加入异步等待队列中,这是okhttp的线程队列优化
5.查看AsyncCall的run方法
AsyncCall 继承了NamedRunnable,其内部会run方法会调用execute(),代码如下

@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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

signalledCallback这个标识用来处理是否打印对应的日志,这里可以看到Response类,说明网络请求是在getResponseWithInterceptorChain中完成的,之后会回调当前的Call状态值
6.真正的网络请求的getResponseWithInterceptorChain

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
   //拦截器集合
    List interceptors = new ArrayList<>();
  //客户端的所有自定义拦截器
    interceptors.addAll(client.interceptors());

  //okhttp自带的拦截器,责任链设计模式,每一个拦截器只处理与它相关的部分
    interceptors.add(retryAndFollowUpInterceptor); //失败重试拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));//request和response拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));//缓存拦截器
    interceptors.add(new ConnectInterceptor(client));//网络请求连接拦截器
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());//网络拦截器
    }
    interceptors.add(new CallServerInterceptor(forWebSocket)); //实际网络请求的拦截器

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

加入各式各样的拦截器,各个拦截器之间不耦合,易于用户的自己配置,最后调用RealInterceptorChain的proceed方法
7.RealInterceptorChain的proceed方法

      HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
      EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
    this.call = call;
    this.eventListener = eventListener;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }
  
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    //...

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // .....

    return response;
  }

构造方法中加入了eventListener事件监听,看来okhttp中eventListener的监听一直延伸到这里,还加入了

  this.connectTimeout = connectTimeout;
  this.readTimeout = readTimeout;
  this.writeTimeout = writeTimeout;

连接时间的配置

要重点关注的是index这个字段,前面传进来的时候,默认是0,而在proceed方法中,又重新执行了RealInterceptorChain的构造方法,并通过 interceptors.get(index)获取下一个拦截器,并且执行interceptor.intercept(next)方法,随便找一个拦截器看看

public final class BridgeInterceptor implements Interceptor {

  @Override public Response intercept(Chain chain) throws IOException {
    //省略部分代码
    Response networkResponse = chain.proceed(requestBuilder.build());
    //省略部分代码
    return responseBuilder.build();
  }
}

拦截器内部又重新调用了chain.proceed的方法,这和递归操作类似,也是okHttp最经典的责任链模式。

8.同步操作

 @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

同步请求也是通过getResponseWithInterceptorChain来完成的,流程更简单
9.大致的流程图


大致的流程图.png

转载:https://blog.csdn.net/lizubing1992/article/details/88841769

你可能感兴趣的:(OkHttp网络请求原理流程解析)