okhttp源码分析

376 阅读2分钟

hello,大家好,这篇文档将会分析当前流行的网络框架okhttp的源码流程

一、基本使用

  // 获得okhttpclient对象	
  OkHttpClient client = new OkHttpClient();
  		// 初始化请求参数
        Request request = new Request.Builder()
                .get()
                .url("http://www.baidu.com")
                .build();
        okhttp3.Call call = client.newCall(request);
        // 执行请求操作
        call.enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                Log.d(TAG,"成功");
            }

            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                Log.d(TAG,"失败");
            }
        });
    }

上诉简简单单的几行代码就完成了一次网络请求操作,很简单。接下来我们开始进行源码分析

二、源码分析

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

我们从请求操作的call.enqueue()方法开始分析,这个方法加了一个同步锁避免多线程的问题。我们再来看一下client.dispatcher()有什么作用。

public final class Dispatcher {
 // 请求最大数量	 
  private int maxRequests = 64;
  // 同一目标主机同时访问最大数量
  private int maxRequestsPerHost = 5;
  private @Nullable Runnable idleCallback;
  /** Executes calls. Created lazily. */
  // 线程池服务
  private @Nullable ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  // 等待执行的请求队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  // 正在执行的异步请求队列
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  // 正在执行的同步请求队列
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

这个类是一个调度者,他的工作是初始化线程池和一些请求队列,接下来我们再来看一的Dispatcher.enqueue()方法

synchronized void enqueue(AsyncCall call) {
	// 正在执行的异步请求是否小于64 && 正在执行的目标主机数量是否小于5 
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      // 添加到正在执行请求的队列
      runningAsyncCalls.add(call);
      // 执行本次请求
      executorService().execute(call);
    } else {
      // 添加到等待队列	
      readyAsyncCalls.add(call);
    }
  }

enqueue()是判断当前请求是否能直接执行还是添加到等待队列中去,好了到了这里简单的请求就完成了。哪它到底是在哪里真正的执行了请求的呢。接下来我们重新回到client.dispatcher().enqueue(new AsyncCall(responseCallback)); enqueue方法传了一个AsyncCall类,它到底是什么呢??接下来,我们来看一下这个类是干什么的

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

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

它是RealCall的一个静态内部类,它的父类是NamedRunnable,接下来我们来看一下它的父类又是干什么的

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

NamedRunnable是一个抽象的类,它实现了Runnable接口,还重写了run()方法并且执行了execute()方法,咦?这个方法不是有点眼熟,好像在哪见过。。。是的,AsyncCall类实现了execute()方法做了真正的实事情。接下来我们来看一看AsyncCall.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);
      }
    }
  }

我们可以看到这方法里拿到了请求之后的返回参数,并且最终回调到了接口,这就代表我们一次完整的网络请求已经结束了。接下来我们看一下它的核心方法 Response response = 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);
  }

getResponseWithInterceptorChain()是初始化了拦截器,并且交予RealInterceptorChain类进行处理

@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 {
    if (index >= interceptors.size()) throw new AssertionError();
	// 记录执行当前方法的次数
    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.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.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    //  index + 1 这里会每次+1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, 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 (httpCodec != 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;
  }

这里会取出拦截器数组中的拦截器进行参数配置,并且调用每个拦截器中的intercept()方法进行当前拦截器的参数封装

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

比如说BridgeInterceptor拦截器的http头参数拼接:Content-Type,Content-Length等。每个拦截器有自己不同的职责,最后拦截器还是会调用chain.proceed(requestBuilder.build());交予下一个拦截器处理自己的职责。当最后一个拦截器处理完之后,它会链式回调给每个拦截器。最终返回到RealCall类的getResponseWithInterceptorChain()方法,调用到回调接口。自此okhttp网络请求结束。

三、总结

总的来说okhttp的主线源码就是这样,其中还有很多细节文章没有介绍到,还需要大家自己分析。好了,这篇文档就到这里了,有什么说的不对的地方希望大家提出来。