面试必问框架之OkHttp源码解析

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("www.baidu.com")
        .build();
try {
    //发送同步请求
    okHttpClient.newCall(request).execute();
    //发送异步请求
    okHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
        @Override
        public void onResponse(Call call, Response response) throws IOException {}
    });
} catch (IOException e) {
    e.printStackTrace();
}

上面这段就是最基础的应用,发送一个get请求。OkHttpClient 有两种创建方式,一种是直接new 一种是OkHttpClient.Builder形式。首先看okHttpClient.newCall(request)

Dispatcher 上层调度

	//方法1 
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
  //方法2
  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;
  }
  // 方法3
  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    this.timeout = new AsyncTimeout() {
      @Override protected void timedOut() {
        cancel();
      }
    };
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

可以看出最终得到的是一个RealCall实例,这个实例对象携带了网络请求的所有信息,包括OkHttpClient Request

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

这是RealCall的同步请求方法,内部就两个核心方法

  1. client.dispatcher().executed(this)
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

是指就是往一个正在运行的同步队列runningSyncCalls添加了一个RealCall
2. getResponseWithInterceptorChain()

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    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);
  }

这个方法是OkHttp 发送请求的核心方法,包括 请求数据 和 拦截器的调用都是通过这个方法的。

@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));
}

void enqueue(AsyncCall call) {
  synchronized (this) {
    readyAsyncCalls.add(call);
  }
  promoteAndExecute();
}

这是异步请求的调用方法,基本和同步请求一样只不过少调用了 getResponseWithInterceptorChain 然后调用了调度器的方法,将RealCall 封装成了一个AsyncCall 对象 然后添加到了readyAsyncCalls 将要开始的异步队列中

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();
	  // 如果runningAsyncCalls 正在请求异步队列 数大于 最大并发数
      if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
      // 如果runningAsyncCalls 正在请求异步队列 请求主机数大于 最大主机数
      if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.

      i.remove();
      //添加到list集合 和 runningAsyncCalls队列
      executableCalls.add(asyncCall);
      runningAsyncCalls.add(asyncCall);
    }
    isRunning = runningCallsCount() > 0;
  }

	// 执行 AsyncCall 
  for (int i = 0, size = executableCalls.size(); i < size; i++) {
    AsyncCall asyncCall = executableCalls.get(i);
    // executorService() 创建一个线程池 执行AsyncCall
    asyncCall.executeOn(executorService());
  }

  return isRunning;
}

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;
}

通过注释可以看到,其实这里做的很简单,就是让一个正在准备异步请求的队列中添加了一个call 也就是request的封装,然后创建了一线程池,最后执行了asyncCall.executeOn

    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
      	// 注释1 执行 ,this实现了AsyncCall extends NamedRunnable 
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
       // 。。。
      } finally {
        if (!success) {
        	// 注释2 如果出现异常 就finish
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

看看他的run方法怎么调用的

//NamedRunnable.java
@Override public final void run() {
  String oldName = Thread.currentThread().getName();
  Thread.currentThread().setName(name);
  try {
    execute();
  } finally {
    Thread.currentThread().setName(oldName);
  }
}
//AsyncCall.java
@Override protected void execute() {
  boolean signalledCallback = false;
  timeout.enter();
  try {
  	// 注释 1 在一次遇到 getResponseWithInterceptorChain 执行请求
    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) {
    e = timeoutExit(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 {
  	//注释2 再一次遇到 dispatcher().finished()
    client.dispatcher().finished(this);
  }
}

getResponseWithInterceptorChain 我们暂且先放置, 先看看dispatcher().finished() 做了什么事。



  private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
	// 核心方法 在上面已经介绍过
    boolean isRunning = promoteAndExecute();

    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }

可以看出它里面依然是执行了promoteAndExecute 类似一个递归调用,不断的去 runningAsyncCalls readyAsyncCalls 中去判断,首先判断正在运行的队列是否达到最大请求量,没达到就把readyAsyncCalls取出一个放进去,用线程池执行。
接下来我们在回头看看 调度器逻辑 我们会发现 他其实就是三个队列 和 两个最大请求量参数。

public final class Dispatcher {
  private int maxRequests = 64; //最大请求数
  private int maxRequestsPerHost = 5; //最大请求主机数
  private @Nullable Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private @Nullable ExecutorService executorService;

  /** 将要执行的异步请求队列 */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 正在准备执行的异步请求队列 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** 正在准备执行的同步请求队列 */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

上面的所有逻辑其实都离不开Dispatcher ,其实就是通过控制 readyAsyncCalls runningAsyncCalls runningSyncCalls 来执行getResponseWithInterceptorChain()Dispatcher 它的核心功能就是管理所有的Call

getResponseWithInterceptorChain()

介绍了OkHttp的上层调度,接下来看看中间它是如何执行的

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    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);
  }

依然回到这段代码 这段代码做了两件事, 第一件 创建了很多拦截器,添加到一个集合中; 第二件 Interceptor.Chain拦截器链 执行了proceed 方法。

// RealInterceptorChain.java
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    calls++;
    // Call the next interceptor in the chain.
    // 注释1 index 最开始等于零 每次new 都加1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    // 注释 2 核心代码
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    return response;
  }

这里就是 getResponseWithInterceptorChain 执行的核心代码位置,也是OkHttp 拦截器设计的精妙之处, 每次都创建一个 Chain 然后把Chain丢着拦截器执行intercept, 然后在拦截器中执行 Chainproceed。 比如我们随便找一个 拦截器。

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();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}

显然这里验证了上面的猜想, 没个拦截器中都加入了一些自己对于 网络请求的判断逻辑, 每个拦截器各司其职完成自己功能。 比如 retryAndFollowUpInterceptor 负责重试相关的操作,ConnectInterceptor 负责链接相关的 操作。一直到执行最后一个操作 CallServerInterceptor 这里是真正请求网络服务器的操作。

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
      	// Expect:100-continue, 询问Server使用愿意接受数据
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());
        long contentLength = request.body().contentLength();
        // 
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        // 调用Okio 然后把request请求 得到一个BufferedSink 输出流
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
		//将请求都写到 buffer里面,这buffer就在request身上
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener()
            .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } else if (!connection.isMultiplexed()) {
       
        streamAllocation.noNewStreams();
      }
    }

    httpCodec.finishRequest();

    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.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
      responseBuilder = httpCodec.readResponseHeaders(false);

      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();

      code = response.code();
    }

    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), 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(httpCodec.openResponseBody(response))
          .build();
    }
	// 省略一部分代码
    return response;
  }

综上的分析这里做的操作就是 调用okio发送出请求信息,然后这个信息就被封装成了一个Response 对象, 但是这个Response 并不是一个实际的结果, 应为实际的结果是在一个buffer 中,最后我们会得到 ResponseBody。 这也是为甚ResponseBody.string() 只能执行一次的原因,因为数据实在一个buffer里面,读一次就就colse了。

发布了58 篇原创文章 · 获赞 16 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dingshuhong_/article/details/104697646