源碼系列--OkHttp

OkHttp官網地址:https://square.github.io/okhttp/java

用法以下:(get請求)git

package okhttp3.guide;

import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class GetExample {
  OkHttpClient client = new OkHttpClient();

  String run(String url) throws IOException {
    Request request = new Request.Builder()
        .url(url)
        .build();

    try (Response response = client.newCall(request).execute()) {
      return response.body().string();
    }
  }

  public static void main(String[] args) throws IOException {
    GetExample example = new GetExample();
    String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
    System.out.println(response);
  }
}

 Github下載源碼地址https://github.com/square/okhttpgithub

4.x以上的版本都大部分更新爲kotlin了,能夠更改分支下載3.x的版原本看web

一。先來看第一步構造函數緩存

OkHttpClient client = new OkHttpClient();

源碼:微信

public OkHttpClient() {
    this(new Builder());
}

Builder()中就是初始化了一堆變量,沒啥東西cookie

二。來看get請求socket

new Request.Builder()

源碼:找內部類Builder的構造函數ide

public Builder() {
  this.method = "GET";
  this.headers = new Headers.Builder();
}

源碼:接着找Headers的內部類Builder,暫時構造了一個變量,尚未作什麼函數

三。下面是執行.url方法,固然是Request內部類Builder的url方法,url暫定爲String

源碼:

public Builder url(String url) {
  if (url == null) throw new NullPointerException("url == null");

  // Silently replace web socket URLs with HTTP URLs.
  if (url.regionMatches(true, 0, "ws:", 0, 3)) {
    url = "http:" + url.substring(3);
  } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
    url = "https:" + url.substring(4);
  }

  return url(HttpUrl.get(url));
}

前面是加前綴,後面去到HttpUrl裏去

public static HttpUrl get(String url) {
    return new Builder().parse(null, url).build();
  }

HttpUrl的內部類Builder的構造函數

public Builder() {
  encodedPathSegments.add(""); // The default path is '/' which needs a trailing space.
}

encodedPathSegments是一個ArrayList

HttpUrl的內部類Builder的parse方法就是一連串的參數解析,你們能夠看源碼

最後一個build()方法

public HttpUrl build() {
  if (scheme == null) throw new IllegalStateException("scheme == null");
  if (host == null) throw new IllegalStateException("host == null");
  return new HttpUrl(this);
}

這個HttpUrl的帶參構造函數中也是一堆變量的初始化

回到Request內部類Builder的url方法

public Builder url(HttpUrl url) {
  if (url == null) throw new NullPointerException("url == null");
  this.url = url;
  return this;
}

接着是Request內部類Builder的build方法

public Request build() {
  if (url == null) throw new IllegalStateException("url == null");
  return new Request(this);
}

Request的帶參構造函數

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

四。接下來很重要了,是執行請求

Response response = client.newCall(request).execute()

OkHttpClient中的newCall方法

@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

進到RealCall中的newRealCall方法

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.transmitter = new Transmitter(client, call);
  return call;
}

構造函數不用管,進去Transmitter中的構造函數

public Transmitter(OkHttpClient client, Call call) {
  this.client = client;
  this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
  this.call = call;
  this.eventListener = client.eventListenerFactory().create(call);
  this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}

其中這個Internal.instance.realConnectionPool(client.connectionPool())能夠找到OkHttpClient的static代碼塊執行後返回了一個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));

 RealConnectionPool一看就知道是0個核心線程,最大值個非核心線程的線程池;這裏還出現了一個Deque雙端隊列,即隊列的升級版,兩個端口均可以進出元素,更加靈活

最後就是RealCall的execute方法了,注意RealCall裏有個內部類AsyncCall也有execute方法,注意不要搞混了

@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  transmitter.timeoutEnter();
  transmitter.callStart();
  try {
    client.dispatcher().executed(this);
    return getResponseWithInterceptorChain();
  } finally {
    client.dispatcher().finished(this);
  }
}

client.dispatcher().executed(this)執行的是

synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

runningSyncCalls就是咱們上面提到的Deque雙端隊列

下面就是最最核心的getResponseWithInterceptorChain方法

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

RetryAndFollowUpInterceptor重試和跳轉攔截器

BridgeInterceptor橋接攔截器,即加請求頭和去響應頭

CacheInterceptor緩存攔截器

ConnectInterceptor鏈接攔截器

CallServerInterceptor調用服務攔截器

List添加好所有Interceptor以後,執行chain.proceed(originalRequest)來到RealInterceptorChain中的proceed方法

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

  // Call the next interceptor in the chain.
  RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
      index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
  Interceptor interceptor = interceptors.get(index);
  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;
}

Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

一開始傳入的index爲0,就是從第一個攔截器開始執行每一個攔截器的intercept方法,index逐次+1

每一個攔截器裏都調用chain.proceed,這樣全部的攔截器就造成鏈條。這裏每一個攔截器的做用就不講了

歡迎關注個人微信公衆號:安卓圈

相關文章
相關標籤/搜索