Okhttp3源码解析

来源:互联网 发布:民治编程语言培训 编辑:程序博客网 时间:2024/06/06 08:31

Okhttp思路解析]![这里写图片描述
上面的图是自己阅读源码整理出来的流程图,具体的会在下面一一讲解和展示出来。
Okhttp是square公司出品的,同时出品的还有Okio,Okio顾名思义就是对IO的处理,毫无疑问,okhttp的IO处理当然也是基于Okio的,后面我也计划写一篇关于Okio的源码解析。扯了这么多,就正式开始我们今天的Okhttp源码解析旅程吧!

OKHttpClient

创建 OkHttpClient 对象

OkHttpClient client = new OkHttpClient();
 static {    Internal.instance = new Internal() {      @Override public void addLenient(Headers.Builder builder, String line) {        builder.addLenient(line);      }      @Override public void addLenient(Headers.Builder builder, String name, String value) {        builder.addLenient(name, value);      }      @Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) {        builder.setInternalCache(internalCache);      }      @Override public boolean connectionBecameIdle(          ConnectionPool pool, RealConnection connection) {        return pool.connectionBecameIdle(connection);      }      @Override public RealConnection get(ConnectionPool pool, Address address,          StreamAllocation streamAllocation, Route route) {        return pool.get(address, streamAllocation, route);      }      @Override public boolean equalsNonHost(Address a, Address b) {        return a.equalsNonHost(b);      }      @Override public Socket deduplicate(          ConnectionPool pool, Address address, StreamAllocation streamAllocation) {        return pool.deduplicate(address, streamAllocation);      }      @Override public void put(ConnectionPool pool, RealConnection connection) {        pool.put(connection);      }      @Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) {        return connectionPool.routeDatabase;      }      @Override public int code(Response.Builder responseBuilder) {        return responseBuilder.code;      }      @Override      public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) {        tlsConfiguration.apply(sslSocket, isFallback);      }      @Override public HttpUrl getHttpUrlChecked(String url)          throws MalformedURLException, UnknownHostException {        return HttpUrl.getChecked(url);      }      @Override public StreamAllocation streamAllocation(Call call) {        return ((RealCall) call).streamAllocation();      }      @Override public Call newWebSocketCall(OkHttpClient client, Request originalRequest) {        return new RealCall(client, originalRequest, true);      }    };  }

打开OkhttpClient源码,最让人注目的就是这一大坨,这些是做什么的呢?先留个悬念,在后面的解析中我们会使用到他,到时候我们再做详解,继续!!!

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

没错,下一个就是他的构造方法,咦??初始化了一个Builder,Bulider又做了些什么东西呢?

 public Builder() {      dispatcher = new Dispatcher();      protocols = DEFAULT_PROTOCOLS;      connectionSpecs = DEFAULT_CONNECTION_SPECS;      eventListenerFactory = EventListener.factory(EventListener.NONE);      proxySelector = ProxySelector.getDefault();      cookieJar = CookieJar.NO_COOKIES;      socketFactory = SocketFactory.getDefault();      hostnameVerifier = OkHostnameVerifier.INSTANCE;      certificatePinner = CertificatePinner.DEFAULT;      proxyAuthenticator = Authenticator.NONE;      authenticator = Authenticator.NONE;      connectionPool = new ConnectionPool();      dns = Dns.SYSTEM;      followSslRedirects = true;      followRedirects = true;      retryOnConnectionFailure = true;      connectTimeout = 10_000;      readTimeout = 10_000;      writeTimeout = 10_000;      pingInterval = 0;    }

在Builder的构造方法里我们需要关注两个类的实例化,一个是dispatcher = new Dispatcher();一个是connectionPool = new ConnectionPool();这两个的实例化会在后面使用,留个印象即可,至此,okhttpclient对象已经创建完毕,接下来就是我们的Request的创建了。

Request创建

Request request = new Request.Builder()      .url(url)      .build();
/** * An HTTP request. Instances of this class are immutable if their {@link #body} is null or itself * immutable. */public final class Request {  final HttpUrl url;  final String method;  final Headers headers;  final @Nullable RequestBody body;  final Object tag;  private volatile CacheControl cacheControl; // Lazily initialized.  Request(Builder builder) {    this.url = builder.url;    this.method = builder.method;    this.headers = builder.headers.build();    this.body = builder.body;    this.tag = builder.tag != null ? builder.tag : this;  }  public HttpUrl url() {    return url;  }  public String method() {    return method;  }  public Headers headers() {    return headers;  }  public String header(String name) {    return headers.get(name);  }  public List<String> headers(String name) {    return headers.values(name);  }  public @Nullable RequestBody body() {    return body;  }  public Object tag() {    return tag;  }  public Builder newBuilder() {    return new Builder(this);  }  /**   * Returns the cache control directives for this response. This is never null, even if this   * response contains no {@code Cache-Control} header.   */  public CacheControl cacheControl() {    CacheControl result = cacheControl;    return result != null ? result : (cacheControl = CacheControl.parse(headers));  }  public boolean isHttps() {    return url.isHttps();  }  @Override public String toString() {    return "Request{method="        + method        + ", url="        + url        + ", tag="        + (tag != this ? tag : null)        + '}';  }  public static class Builder {    HttpUrl url;    String method;    Headers.Builder headers;    RequestBody body;    Object tag;    public Builder() {      this.method = "GET";      this.headers = new Headers.Builder();    }    Builder(Request request) {      this.url = request.url;      this.method = request.method;      this.body = request.body;      this.tag = request.tag;      this.headers = request.headers.newBuilder();    }    public Builder url(HttpUrl url) {      if (url == null) throw new NullPointerException("url == null");      this.url = url;      return this;    }    /**     * Sets the URL target of this request.     *     * @throws IllegalArgumentException if {@code url} is not a valid HTTP or HTTPS URL. Avoid this     * exception by calling {@link HttpUrl#parse}; it returns null for invalid URLs.     */    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);      }      HttpUrl parsed = HttpUrl.parse(url);      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);      return url(parsed);    }    /**     * Sets the URL target of this request.     *     * @throws IllegalArgumentException if the scheme of {@code url} is not {@code http} or {@code     * https}.     */    public Builder url(URL url) {      if (url == null) throw new NullPointerException("url == null");      HttpUrl parsed = HttpUrl.get(url);      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);      return url(parsed);    }    /**     * Sets the header named {@code name} to {@code value}. If this request already has any headers     * with that name, they are all replaced.     */    public Builder header(String name, String value) {      headers.set(name, value);      return this;    }    /**     * Adds a header with {@code name} and {@code value}. Prefer this method for multiply-valued     * headers like "Cookie".     *     * <p>Note that for some headers including {@code Content-Length} and {@code Content-Encoding},     * OkHttp may replace {@code value} with a header derived from the request body.     */    public Builder addHeader(String name, String value) {      headers.add(name, value);      return this;    }    public Builder removeHeader(String name) {      headers.removeAll(name);      return this;    }    /** Removes all headers on this builder and adds {@code headers}. */    public Builder headers(Headers headers) {      this.headers = headers.newBuilder();      return this;    }    /**设置缓存策略     * Sets this request's {@code Cache-Control} header, replacing any cache control headers already     * present. If {@code cacheControl} doesn't define any directives, this clears this request's     * cache-control headers.     */    public Builder cacheControl(CacheControl cacheControl) {      String value = cacheControl.toString();      if (value.isEmpty()) return removeHeader("Cache-Control");      return header("Cache-Control", value);    }    public Builder get() {      return method("GET", null);    }    public Builder head() {      return method("HEAD", null);    }    public Builder post(RequestBody body) {      return method("POST", body);    }    public Builder delete(@Nullable RequestBody body) {      return method("DELETE", body);    }    public Builder delete() {      return delete(Util.EMPTY_REQUEST);    }    public Builder put(RequestBody body) {      return method("PUT", body);    }    public Builder patch(RequestBody body) {      return method("PATCH", body);    }    public Builder method(String method, @Nullable RequestBody body) {      if (method == null) throw new NullPointerException("method == null");      if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");      if (body != null && !HttpMethod.permitsRequestBody(method)) {        throw new IllegalArgumentException("method " + method + " must not have a request body.");      }      if (body == null && HttpMethod.requiresRequestBody(method)) {        throw new IllegalArgumentException("method " + method + " must have a request body.");      }      this.method = method;      this.body = body;      return this;    }    /**     * Attaches {@code tag} to the request. It can be used later to cancel the request. If the tag     * is unspecified or null, the request is canceled by using the request itself as the tag.     */    public Builder tag(Object tag) {      this.tag = tag;      return this;    }    public Request build() {      if (url == null) throw new IllegalStateException("url == null");      return new Request(this);    }  }}

可以看出,Request采用的构建者模式,没有什么可讲的,要说知识点的话,就是缓存。okhttp提供了两种缓存策略,一个是拦截器缓存(client层处理),一个是CacheControl缓存(request层处理),

缓存拦截器

 class MyCacheInterceptor implements Interceptor{        @Override        public Response intercept(Chain chain) throws IOException {            Response originalResponse=chain.proceed(chain.request());            return originalResponse.newBuilder().removeHeader("prama").header("Cache-Control","max-age=60").build();        }    }

定义好拦截器中后,我们可以添加到OKHttpClient中了。

OkHttpClient okHttpClient=new OkHttpClient.Builder()                          .addNetworkInterceptor(new MyCacheInterceptor())                          .build();

CacheControl

okhttp中建议用 CacheControl 这个类来进行缓存策略的制定。它内部有两个很重要的静态实例。

/**强制使用网络请求   * Cache control request directives that require network validation of responses. Note that such   * requests may be assisted by the cache via conditional GET requests.   */  public static final CacheControl FORCE_NETWORK = new Builder().noCache().build();  /**强制使用本地缓存   * Cache control request directives that uses the cache only, even if the cached response is   * stale. If the response isn't available in the cache or requires server validation, the call   * will fail with a {@code 504 Unsatisfiable Request}.   */  public static final CacheControl FORCE_CACHE = new Builder()      .onlyIfCached()      .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)      .build();

使用方法如下:

Request request = new Request.Builder()                .url("")                //强制使用缓存                //.cacheControl(CacheControl.FORCE_CACHE)                //强制使用网络                .cacheControl(CacheControl.FORCE_NETWORK)                .build();

发起 HTTP 请求

//同步请求Response response = client.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 {            }        });

无论是同步请求还是异步请求,都是由newCall调起的,那我们就看一下newCall的内部实现:

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

如此看来功劳全在 RealCall 类了,下面我们一边分析同步网络请求的过程,一边了解 RealCall 的具体内容。

final class RealCall implements Call {  final OkHttpClient client;  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;  final EventListener eventListener;  /** The application's original request unadulterated by redirects or auth headers. */  final Request originalRequest;  final boolean forWebSocket;  // Guarded by this.  private boolean executed;  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();    this.client = client;    this.originalRequest = originalRequest;    this.forWebSocket = forWebSocket;    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);    // TODO(jwilson): this is unsafe publication and not threadsafe.    this.eventListener = eventListenerFactory.create(this);  }  //同步请求  @Override public Response execute() throws IOException {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    try {      client.dispatcher().executed(this);                      (1)      Response result = getResponseWithInterceptorChain();     (2if (result == null) throw new IOException("Canceled");      return result;    } finally {      client.dispatcher().finished(this);    }  }  //异步请求  @Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    client.dispatcher().enqueue(new AsyncCall(responseCallback));(1)  }  private void captureCallStackTrace() {    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);  }}

这里只截取了关键的代码块。
同步请求:
(1)利用 client.dispatcher().executed(this) 来进行实际执行
(2)调用 getResponseWithInterceptorChain() 函数获取 HTTP 返回结果
(3)最后还要通知 dispatcher 自己已经执行完毕
异步请求:
(1)调用dispathcher.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();   (1if (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 {          responseCallback.onFailure(RealCall.this, e);        }      } finally {        client.dispatcher().finished(this);      }    }  }
/** * Runnable implementation which always sets its thread name. */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();}

由源码可以看出,其实AsyncCall就是一个线程,线程的execute方法里面同样调用getResponseWithInterceptorChain()获取Response。由此可以看出,无论是同步请求,还是异步请求都是通过getResponseWithInterceptorChain()方法获取Response的,毫无疑问,必须要看看内部如何实现的:

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);    return chain.proceed(originalRequest);  }

卧槽,竟然是一系列的拦截器组成的,所以下面的重点就是搞清楚每个拦截器的功能。由于篇幅的原因,下面专门用一篇博客讲解拦截器。敬请期待!!!!!

原创粉丝点击