• Android之OKHttp源码解析


    一、OKHttp的基本使用

    基本的使用流程如下

    // 实例OkHttpClient
    var okHttpClient = OkHttpClient()
    // 构建请求体
    val body = FormBody.Builder().build()
    // 生成Request
    val request = Request.Builder().url("api地址").post(body).build()
    // 同步请求
    val resopnse = okHttpClient.newCall(request).execute()
    // 获取同步请求结果
    String retJson = response.body().string();
    // 异步请求
    okHttpClient.newCall(request).enqueue(object : Callback{
        override fun onFailure(call: Call, e: IOException) {
            //请求失败
        }
    
        override fun onResponse(call: Call, response: Response) {
            //请求成功
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二、使用流程源码分析

    同步请求流程分析

    // newCall实例一个RealCall
    @Override public Call newCall(Request request) {
      return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    // 执行realCall的execute
    @Override public Response execute() throws IOException {
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
      }
      transmitter.timeoutEnter();
      transmitter.callStart();
      try {
        // 从okHttpClient中取出分发器调用executed
        client.dispatcher().executed(this);
        // 直接调用RealCall的拦截器 执行流程后面会讲到
        return getResponseWithInterceptorChain();
      } finally {
        client.dispatcher().finished(this);
      }
    }
    
    //Dispatcher中将 RealCall 放置 runningSyncCalls 同步双向队列
    synchronized void executed(RealCall call) {
      runningSyncCalls.add(call);
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    异步请求流程分析

    // RealCall.java
    
    @Override public void enqueue(Callback responseCallback) {
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
      }
      transmitter.callStart();
      // 这里传入一个AsyncCall
      client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里与同步请求的excute有些不同

    1. 调用的是分发器Dispatcher的enquene函数
    2. 并没有开始执行拦截器

    那异步请求流程中Dispatcher中做了什么?

    三、OKHttp分发器Dispatcher

    从上面的执行流程源码我们可以了解到在进行同步请求excute 时只是调用了Dispatcher的executed方法,将同步请求放置到同步双端队列中,这里并没有体现"分发"的作用,而在进行异步请求enquene时,调用了Dispatcher的enqueue方法,这里接着看源码:

    // Dispatcher.java 
    
    // 用于放置等待中的异步任务的等待任务队列
    private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    
    // 用于放置执行中的异步任务的队列
    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
    
    // 用于放置执行中的同步任务队列
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    
    // 线程池
    private @Nullable ExecutorService executorService;
    // 可以通过构造函数进行线程池赋值
    public Dispatcher(ExecutorService executorService) {
      this.executorService = executorService;
    }
    
    void enqueue(AsyncCall call) {
      synchronized (this) {
        //将任务放置在等待队列中
        readyAsyncCalls.add(call);
    
        // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
        // the same host.
        if (!call.get().forWebSocket) {
          AsyncCall existingCall = findExistingCallWithHost(call.host());
          if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
        }
      }
      // 根据队列状态协调处理任务
      promoteAndExecute();
    }
    
    
    private boolean promoteAndExecute() {
      assert (!Thread.holdsLock(this));
    
      List<AsyncCall> executableCalls = new ArrayList<>();
      boolean isRunning;
      synchronized (this) {
        for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
          AsyncCall asyncCall = i.next();
          // 等待队列数量是否已达到最大容量maxRequests(64)
          if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
          // 相同host的请求数是否已达到最大容量maxRequestsPerHost(5)
          if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
          // 从等待队列中移除
          i.remove();
          asyncCall.callsPerHost().incrementAndGet();
          // 加入到要被线程池执行的任务集合中
          executableCalls.add(asyncCall);
          // 加入到执行中队列
          runningAsyncCalls.add(asyncCall);
        }
        isRunning = runningCallsCount() > 0;
      }
    
      for (int i = 0, size = executableCalls.size(); i < size; i++) {
        AsyncCall asyncCall = executableCalls.get(i);
        // 调用执行函数 传入执行服务线程池
        asyncCall.executeOn(executorService());
      }
    
      return isRunning;
    }
    
    public synchronized ExecutorService executorService() {
      // 如果当前线程池为null,则创建
      if (executorService == null) {
      // 创建一个跟CachedThreadPool大致相同的线程池
        executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
            new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
      }
      return executorService;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    首先会将异步任务存储到readyAsyncCalls等待队列中,其后会调用promoteAndExecute进行任务的分发,根据执行队列的请求数量最大阈值和请求相同host的数量进行一个条件判断,根据结果决定要不要把任务放置runningAsyncCalls执行队列中,以及直接调用executorService创建线程池用于任务的执行,到这里我们可以总结Dispatcher的任务就是管理三个任务队列的任务分发以及一个线程池的创建。

    asyncCall.executeOn(executorService())的执行逻辑如下:

    //AsyncCall.java
    
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        //线程池执行任务
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }
    
    //AsnycCall执行时的核心逻辑
    @Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        //执行拦截器
        Response response = getResponseWithInterceptorChain();
        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);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        //异步任务完成时通知分发器中的队列移除任务
        client.dispatcher().finished(this);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    到这里,我们基本理清楚了异步调用的一个链路:

    WeChata3d1e14c77a28a0d0a5cb4b25fcb1e22.png

    AsyncCall.excute()内部的拦截器又是如何开始工作的呢?

    四、OKHttp拦截器

    Response getResponseWithInterceptorChain() throws IOException {
      // 拦截器集合
      List<Interceptor> interceptors = new ArrayList<>();
      // 添加开发者自定义的拦截器(常用的log、公共参数、json解析等)
      interceptors.addAll(client.interceptors());
      // 重试拦截器
      interceptors.add(new RetryAndFollowUpInterceptor(client));
      // 桥接拦截器
      interceptors.add(new BridgeInterceptor(client.cookieJar()));
      // 缓存拦截器
      interceptors.add(new CacheInterceptor(client.internalCache()));
      // 建立连接的拦截器
      interceptors.add(new ConnectInterceptor(client));
      if (!forWebSocket) {
      // 非webSocket 添加网络拦截器
        interceptors.addAll(client.networkInterceptors());
      }
      // 处理请求服务端的拦截器
      interceptors.add(new CallServerInterceptor(forWebSocket));
      // 责任链对象实例
      Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
          originalRequest, this, client.connectTimeoutMillis(),
          client.readTimeoutMillis(), client.writeTimeoutMillis());
    
      boolean calledNoMoreExchanges = false;
      try {
        // 开启责任链的调用  
        Response response = chain.proceed(originalRequest);
        if (transmitter.isCanceled()) {
          closeQuietly(response);
          throw new IOException("Canceled");
        }
        return response;
      } catch (IOException e) {
        calledNoMoreExchanges = true;
        throw transmitter.noMoreExchanges(e);
      } finally {
        if (!calledNoMoreExchanges) {
          transmitter.noMoreExchanges(null);
        }
      }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    先说一下责任链是如何调用起来的,在getResponseWithInterceptorChain中会把所有拦截器装进集合中,再将拦截器集合以及集合的初始索引也就是0等一些参数传入到实例的责任链对象RealInterceptorChain,然后调用责任链对象的procrss开启拦截器执行

    // 责任链对象构造函数
    public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
        @Nullable Exchange exchange, int index, Request request, Call call,
        int connectTimeout, int readTimeout, int writeTimeout) {
      // 拦截器集合
      this.interceptors = interceptors;
      this.transmitter = transmitter;
      this.exchange = exchange;
      // 责任链对象对应的拦截器集合中的索引
      this.index = index;
      this.request = request;
      this.call = call;
      this.connectTimeout = connectTimeout;
      this.readTimeout = readTimeout;
      this.writeTimeout = writeTimeout;
    }
    //执行责任链
    public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
        throws IOException {
      if (index >= interceptors.size()) throw new AssertionError();
    
      calls++;
    
      // If we already have a stream, confirm that the incoming request will use it.
      if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
        throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
            + " must retain the same host and port");
      }
    
      // If we already have a stream, confirm that this is the only call to chain.proceed().
      if (this.exchange != null && calls > 1) {
        throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
            + " must call proceed() exactly once");
      }
    
      // 实例化责任链对象,将拦截器集合中的索引+1,也就是当前责任链对象的下一个责任链,对应下一个拦截器
      RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
          index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
      // 取出当前责任链对应的拦截器    
      Interceptor interceptor = interceptors.get(index);
      // 在当前责任链对应的拦截器调用intercept函数中传入下一个责任链对象
      Response response = interceptor.intercept(next);
    
      // Confirm that the next interceptor made its required call to chain.proceed().
      if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
        throw new IllegalStateException("network interceptor " + interceptor
            + " must call proceed() exactly once");
      }
    
      // Confirm that the intercepted response isn't null.
      if (response == null) {
        throw new NullPointerException("interceptor " + interceptor + " returned null");
      }
    
      if (response.body() == null) {
        throw new IllegalStateException(
            "interceptor " + interceptor + " returned a response with no body");
      }
    
      return response;
    }
    
    //重试拦截器
    public final class RetryAndFollowUpInterceptor implements Interceptor {
      /**
       * How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox,
       * curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5.
       */
      private static final int MAX_FOLLOW_UPS = 20;
    
      private final OkHttpClient client;
    
      public RetryAndFollowUpInterceptor(OkHttpClient client) {
        this.client = client;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Transmitter transmitter = realChain.transmitter();
    
        int followUpCount = 0;
        Response priorResponse = null;
        while (true) {
          transmitter.prepareToConnect(request);
    
          if (transmitter.isCanceled()) {
            throw new IOException("Canceled");
          }
    
          Response response;
          boolean success = false;
          try {
            // 执行下一个责任链对象的proceed方法
            response = realChain.proceed(request, transmitter, null);
            success = true;
          } catch (RouteException e) {
            // The attempt to connect via a route failed. The request will not have been sent.
            if (!recover(e.getLastConnectException(), transmitter, false, request)) {
              throw e.getFirstConnectException();
            }
            continue;
          } catch (IOException e) {
            // An attempt to communicate with a server failed. The request may have been sent.
            boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
            if (!recover(e, transmitter, requestSendStarted, request)) throw e;
            continue;
          } finally {
            // The network call threw an exception. Release any resources.
            if (!success) {
              transmitter.exchangeDoneDueToException();
            }
          }
    
          // Attach the prior response if it exists. Such responses never have a body.
          if (priorResponse != null) {
            response = response.newBuilder()
                .priorResponse(priorResponse.newBuilder()
                        .body(null)
                        .build())
                .build();
          }
    
          Exchange exchange = Internal.instance.exchange(response);
          Route route = exchange != null ? exchange.connection().route() : null;
          Request followUp = followUpRequest(response, route);
    
          if (followUp == null) {
            if (exchange != null && exchange.isDuplex()) {
              transmitter.timeoutEarlyExit();
            }
            return response;
          }
    
          RequestBody followUpBody = followUp.body();
          if (followUpBody != null && followUpBody.isOneShot()) {
            return response;
          }
    
          closeQuietly(response.body());
          if (transmitter.hasExchange()) {
            exchange.detachWithViolence();
          }
    
          if (++followUpCount > MAX_FOLLOW_UPS) {
            throw new ProtocolException("Too many follow-up requests: " + followUpCount);
          }
    
          request = followUp;
          priorResponse = response;
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152

    每一个责任链对象都对应一个拦截器,比如在我们没有自定义拦截器时,初始责任链0对应拦截器集合索引0,也就是重试拦截器,在重试拦截器的intercept中又调用下一个责任链对象1的procees,也就会对应执行拦截器集合中索引为1桥接拦截器的intercept,以此类推,就会完成整个责任链节点的调用,但是在责任链的调用链路中,不一定会全部执行,在一些场景下,拦截器可能会直接返回一个response对象结束责任链调用,下面会讲到,在重试拦截器中,会进入一个while(true)循环,重复执行重试拦截器后续的拦截器,如果开启重试机制则会直到达到重试阈值或返回了一个满足条件的结果。

    桥接拦截器BridgeInterceptor

    public final class BridgeInterceptor implements Interceptor {
      private final CookieJar cookieJar;
    
      public BridgeInterceptor(CookieJar cookieJar) {
        this.cookieJar = cookieJar;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();
        Request.Builder requestBuilder = userRequest.newBuilder();
    
        RequestBody body = userRequest.body();
        if (body != null) {
          MediaType contentType = body.contentType();
          if (contentType != null) {
            requestBuilder.header("Content-Type", contentType.toString());
          }
    
          long contentLength = body.contentLength();
          if (contentLength != -1) {
            requestBuilder.header("Content-Length", Long.toString(contentLength));
            requestBuilder.removeHeader("Transfer-Encoding");
          } else {
            requestBuilder.header("Transfer-Encoding", "chunked");
            requestBuilder.removeHeader("Content-Length");
          }
        }
    
        if (userRequest.header("Host") == null) {
          requestBuilder.header("Host", hostHeader(userRequest.url(), false));
        }
    
        if (userRequest.header("Connection") == null) {
          requestBuilder.header("Connection", "Keep-Alive");
        }
    
        // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
        // the transfer stream.
        boolean transparentGzip = false;
        if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
          transparentGzip = true;
          requestBuilder.header("Accept-Encoding", "gzip");
        }
    
        List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
        if (!cookies.isEmpty()) {
          requestBuilder.header("Cookie", cookieHeader(cookies));
        }
    
        if (userRequest.header("User-Agent") == null) {
          requestBuilder.header("User-Agent", Version.userAgent());
        }
    
        Response networkResponse = chain.proceed(requestBuilder.build());
    
        HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    
        Response.Builder responseBuilder = networkResponse.newBuilder()
            .request(userRequest);
    
        if (transparentGzip
            && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
            && HttpHeaders.hasBody(networkResponse)) {
          GzipSource responseBody = new GzipSource(networkResponse.body().source());
          Headers strippedHeaders = networkResponse.headers().newBuilder()
              .removeAll("Content-Encoding")
              .removeAll("Content-Length")
              .build();
          responseBuilder.headers(strippedHeaders);
          String contentType = networkResponse.header("Content-Type");
          responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
        }
    
        return responseBuilder.build();
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    桥接拦截器的作用从代码中可以看出,主要是对请求和响应进行一个包装,形成规范。

    缓存拦截器CacheInterceptor

    /** Serves requests from the cache and writes responses to the cache. */
    public final class CacheInterceptor implements Interceptor {
      final @Nullable InternalCache cache;
    
      public CacheInterceptor(@Nullable InternalCache cache) {
        this.cache = cache;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        Response cacheCandidate = cache != null
            ? cache.get(chain.request())
            : null;
    
        long now = System.currentTimeMillis();
    
        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
        Request networkRequest = strategy.networkRequest;
        Response cacheResponse = strategy.cacheResponse;
    
        if (cache != null) {
          cache.trackResponse(strategy);
        }
        if (cacheCandidate != null && cacheResponse == null) {
          closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
        }
    
        // 如果请求不开启网络且不使用缓存
        if (networkRequest == null && cacheResponse == null) {
        // 直接返回一个response结束责任链
          return new Response.Builder()
              .request(chain.request())
              .protocol(Protocol.HTTP_1_1)
              .code(504)
              .message("Unsatisfiable Request (only-if-cached)")
              .body(Util.EMPTY_RESPONSE)
              .sentRequestAtMillis(-1L)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();
        }
    
        // 如果仅仅不开启网络,但是开启了缓存,直接返回缓存的结果
        if (networkRequest == null) {
          return cacheResponse.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build();
        }
    
        Response networkResponse = null;
        try {
          //下一个责任链调用,对应ConnectInterceptor
          networkResponse = chain.proceed(networkRequest);
        } finally {
          // If we're crashing on I/O or otherwise, don't leak the cache body.
          if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }
    
        // If we have a cache response too, then we're doing a conditional get.
        if (cacheResponse != null) {
          if (networkResponse.code() == HTTP_NOT_MODIFIED) {
            Response response = cacheResponse.newBuilder()
                .headers(combine(cacheResponse.headers(), networkResponse.headers()))
                .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
                .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
                .cacheResponse(stripBody(cacheResponse))
                .networkResponse(stripBody(networkResponse))
                .build();
            networkResponse.body().close();
    
            // Update the cache after combining headers but before stripping the
            // Content-Encoding header (as performed by initContentStream()).
            cache.trackConditionalCacheHit();
            cache.update(cacheResponse, response);
            return response;
          } else {
            closeQuietly(cacheResponse.body());
          }
        }
    
        Response response = networkResponse.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
    
        if (cache != null) {
          if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
            // Offer this request to the cache.
            CacheRequest cacheRequest = cache.put(response);
            return cacheWritingResponse(cacheRequest, response);
          }
    
          if (HttpMethod.invalidatesCache(networkRequest.method())) {
            try {
              cache.remove(networkRequest);
            } catch (IOException ignored) {
              // The cache cannot be written.
            }
          }
        }
    
        return response;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    从代码中可以看出,缓存拦截器在一些场景下回直接中断拦截器的调用,返回结果。

    连接拦截器ConnectInterceptor

    连接拦截器是拦截器中比较关键的一环,涉及到了连接池的管理

    /** Opens a connection to the target server and proceeds to the next interceptor. */
    public final class ConnectInterceptor implements Interceptor {
      public final OkHttpClient client;
    
      public ConnectInterceptor(OkHttpClient client) {
        this.client = client;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        Transmitter transmitter = realChain.transmitter();
    
        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
    
        return realChain.proceed(request, transmitter, exchange);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    连接的获取是在transmitter.newExchange()执行到ExChangeFinder中的findConnection()

    private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
        int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
      boolean foundPooledConnection = false;
      RealConnection result = null;
      Route selectedRoute = null;
      RealConnection releasedConnection;
      Socket toClose;
      synchronized (connectionPool) {
        if (transmitter.isCanceled()) throw new IOException("Canceled");
        hasStreamFailure = false; // This is a fresh attempt.
    
        // 获取一个已经存在的连接
        releasedConnection = transmitter.connection;
        // 已经存在的连接可能已经不可用
        toClose = transmitter.connection != null && transmitter.connection.noNewExchanges
            ? transmitter.releaseConnectionNoEvents()
            : null;
    
        if (transmitter.connection != null) {
          //存在的连接可用
          result = transmitter.connection;
          releasedConnection = null;
        }
    
        if (result == null) {
          // 尝试从连接池中取获取
          if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
            foundPooledConnection = true;
            result = transmitter.connection;
          } else if (nextRouteToTry != null) {
            selectedRoute = nextRouteToTry;
            nextRouteToTry = null;
          } else if (retryCurrentRoute()) {
            selectedRoute = transmitter.connection.route();
          }
        }
      }
      closeQuietly(toClose);
    
      if (releasedConnection != null) {
        eventListener.connectionReleased(call, releasedConnection);
      }
      if (foundPooledConnection) {
        eventListener.connectionAcquired(call, result);
      }
      if (result != null) {
        // 已经有存在的连接可复用 直接返回
        return result;
      }
    
      // If we need a route selection, make one. This is a blocking operation.
      boolean newRouteSelection = false;
      if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
        newRouteSelection = true;
        routeSelection = routeSelector.next();
      }
    
      List<Route> routes = null;
      synchronized (connectionPool) {
        if (transmitter.isCanceled()) throw new IOException("Canceled");
    
        if (newRouteSelection) {
          // Now that we have a set of IP addresses, make another attempt at getting a connection from
          // the pool. This could match due to connection coalescing.
          routes = routeSelection.getAll();
          if (connectionPool.transmitterAcquirePooledConnection(
              address, transmitter, routes, false)) {
            foundPooledConnection = true;
            result = transmitter.connection;
          }
        }
    
        if (!foundPooledConnection) {
          if (selectedRoute == null) {
            selectedRoute = routeSelection.next();
          }
    
          // 没有可用连接则新建
          result = new RealConnection(connectionPool, selectedRoute);
          connectingConnection = result;
        }
      }
    
      // If we found a pooled connection on the 2nd time around, we're done.
      if (foundPooledConnection) {
        eventListener.connectionAcquired(call, result);
        return result;
      }
    
      // Do TCP + TLS handshakes. This is a blocking operation.
      result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
          connectionRetryEnabled, call, eventListener);
      connectionPool.routeDatabase.connected(result.route());
    
      Socket socket = null;
      synchronized (connectionPool) {
        connectingConnection = null;
        // Last attempt at connection coalescing, which only occurs if we attempted multiple
        // concurrent connections to the same host.
        if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
          // We lost the race! Close the connection we created and return the pooled connection.
          result.noNewExchanges = true;
          socket = result.socket();
          result = transmitter.connection;
    
          // It's possible for us to obtain a coalesced connection that is immediately unhealthy. In
          // that case we will retry the route we just successfully connected with.
          nextRouteToTry = selectedRoute;
        } else {
        // 将新建连接放置连接池
          connectionPool.put(result);
          transmitter.acquireConnectionNoEvents(result);
        }
      }
      closeQuietly(socket);
    
      eventListener.connectionAcquired(call, result);
      return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119

    一个连接的获取流程为:

    1. 尝试使用当前连接,但是连接可能不用
    2. 从连接池中获取连接,如果有缓存的话
    3. 新建一个连接,并放置到连接池

    而连接在连接池的释放流程为:

    public final class RealConnectionPool {
    
        private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
            Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
            new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));
        // 将连接放置连接池
        void put(RealConnection connection) {
          assert (Thread.holdsLock(this));
          if (!cleanupRunning) {
            cleanupRunning = true;
            // 线程池执行连接池的清理任务
            executor.execute(cleanupRunnable);
          }
          // 将连接放置连接池
          connections.add(connection);
        }
    }
    // 连接池的清理任务
    private final Runnable cleanupRunnable = () -> {
      // 开启循环检测
      while (true) {
        // 清理方法  
        long waitNanos = cleanup(System.nanoTime());
        if (waitNanos == -1) return;
        if (waitNanos > 0) {
          long waitMillis = waitNanos / 1000000L;
          waitNanos -= (waitMillis * 1000000L);
          synchronized (RealConnectionPool.this) {
            try {
              RealConnectionPool.this.wait(waitMillis, (int) waitNanos);
            } catch (InterruptedException ignored) {
            }
          }
        }
      }
    };
    
    long cleanup(long now) {
      int inUseConnectionCount = 0;
      int idleConnectionCount = 0;
      RealConnection longestIdleConnection = null;
      long longestIdleDurationNs = Long.MIN_VALUE;
    
      // Find either a connection to evict, or the time that the next eviction is due.
      synchronized (this) {
        for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
          RealConnection connection = i.next();
    
          // If the connection is in use, keep searching.
          if (pruneAndGetAllocationCount(connection, now) > 0) {
            inUseConnectionCount++;
            continue;
          }
    
          idleConnectionCount++;
    
          // If the connection is ready to be evicted, we're done.
          long idleDurationNs = now - connection.idleAtNanos;
          if (idleDurationNs > longestIdleDurationNs) {
            longestIdleDurationNs = idleDurationNs;
            longestIdleConnection = connection;
          }
        }
    
        if (longestIdleDurationNs >= this.keepAliveDurationNs
            || idleConnectionCount > this.maxIdleConnections) {
          // 清理连接
          connections.remove(longestIdleConnection);
        } else if (idleConnectionCount > 0) {
          // A connection will be ready to evict soon.
          return keepAliveDurationNs - longestIdleDurationNs;
        } else if (inUseConnectionCount > 0) {
          // All connections are in use. It'll be at least the keep alive duration 'til we run again.
          return keepAliveDurationNs;
        } else {
          // No connections, idle or in use.
          cleanupRunning = false;
          return -1;
        }
      }
    
      closeQuietly(longestIdleConnection.socket());
    
      // Cleanup again immediately.
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    maxIdleConnectionskeepAliveDurationNs,分别表示最大允许的闲置的连接的数量和连接允许存活的最长的时间。默认空闲连接最大数目为5个,keepalive 时间最长为5分钟。

    请求服务拦截器CallServerInterceptor

    public final class CallServerInterceptor implements Interceptor {
      private final boolean forWebSocket;
    
      public CallServerInterceptor(boolean forWebSocket) {
        this.forWebSocket = forWebSocket;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Exchange exchange = realChain.exchange();
        Request request = realChain.request();
    
        long sentRequestMillis = System.currentTimeMillis();
    
        exchange.writeRequestHeaders(request);
    
        boolean responseHeadersStarted = false;
        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
          // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
          // Continue" response before transmitting the request body. If we don't get that, return
          // what we did get (such as a 4xx response) without ever transmitting the request body.
          if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
            exchange.flushRequest();
            responseHeadersStarted = true;
            exchange.responseHeadersStart();
            responseBuilder = exchange.readResponseHeaders(true);
          }
    
          if (responseBuilder == null) {
            if (request.body().isDuplex()) {
              // Prepare a duplex body so that the application can send a request body later.
              exchange.flushRequest();
              BufferedSink bufferedRequestBody = Okio.buffer(
                  exchange.createRequestBody(request, true));
              request.body().writeTo(bufferedRequestBody);
            } else {
              // Write the request body if the "Expect: 100-continue" expectation was met.
              BufferedSink bufferedRequestBody = Okio.buffer(
                  exchange.createRequestBody(request, false));
              request.body().writeTo(bufferedRequestBody);
              bufferedRequestBody.close();
            }
          } else {
            exchange.noRequestBody();
            if (!exchange.connection().isMultiplexed()) {
              // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
              // from being reused. Otherwise we're still obligated to transmit the request body to
              // leave the connection in a consistent state.
              exchange.noNewExchangesOnConnection();
            }
          }
        } else {
          exchange.noRequestBody();
        }
    
        if (request.body() == null || !request.body().isDuplex()) {
          exchange.finishRequest();
        }
    
        if (!responseHeadersStarted) {
          exchange.responseHeadersStart();
        }
    
        if (responseBuilder == null) {
          responseBuilder = exchange.readResponseHeaders(false);
        }
    
        Response response = responseBuilder
            .request(request)
            .handshake(exchange.connection().handshake())
            .sentRequestAtMillis(sentRequestMillis)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build();
    
        int code = response.code();
        if (code == 100) {
          // server sent a 100-continue even though we did not request one.
          // try again to read the actual response
          response = exchange.readResponseHeaders(false)
              .request(request)
              .handshake(exchange.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();
    
          code = response.code();
        }
    
        exchange.responseHeadersEnd(response);
    
        if (forWebSocket && code == 101) {
          // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
          response = response.newBuilder()
              .body(Util.EMPTY_RESPONSE)
              .build();
        } else {
          response = response.newBuilder()
              .body(exchange.openResponseBody(response))
              .build();
        }
    
        if ("close".equalsIgnoreCase(response.request().header("Connection"))
            || "close".equalsIgnoreCase(response.header("Connection"))) {
          exchange.noNewExchangesOnConnection();
        }
    
        if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
          throw new ProtocolException(
              "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
        }
    
        return response;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

    请求服务拦截器是拦截器集合中的最后一环,网络请求也是在此进行的操作,在请求完成后会返回response进行回传,最终就是getResponseWithInterceptorChain的返回结果。

    至此,okHttp的解析就到这里了,有不对的地方欢迎大家指出,篇幅有点长,有觉得有所帮助的话大家可以点赞收藏哦~

  • 相关阅读:
    ElasticSearch (一)ElasticSearch 入门简介
    vim编辑器
    【服务器】Java连接redis及使用Java操作redis、使用场景
    计算机组装与维护实训室解决方案
    文件上传漏洞
    Android databinding之RecycleView使用与介绍(二)
    如何处理Vue2项目里大规模的数据计算?
    NLog笔记
    openvino学习(一)ubuntu20.04安装openvino2022
    linux虚拟文件系统
  • 原文地址:https://blog.csdn.net/m0_62167422/article/details/125492748