Okhttp同步Get分析

2018-04-03  本文已影响0人  夕日的欢笑

下面介绍下流程图中用到的类的主要作用

OkhttpClient:所有请求的客户端类,一般只创建一次作为全局实例保存

Request:主要是封装请求报文信息url,请求方法,各种请求头等。

RealCall:代表一个实际的http请求,是链接request和respone的桥梁

Despatcher:决定了同步或者异步请求,它的内部维护了一个线程池用来执行网络请求,内部有三个队列维护同步或者异步请求,despatcher不    断的从request队列中获取Realcall,然后通过拦截器连是否复用缓存,如果不复用就从服务器获取数据

Interceptors:拦截器连依次执行拦截器连中的每个拦截器将服务器的数据返回。

RetryAndFollow:网络连接失败后重连,重定向。

Bridge:主要是设置内容长度,编码,压缩格式,添加cookies,设置报头等主要是请求前的操作。

Cache:主要负责缓存的管理,当网络请求有符合的缓存请求,直接返回cache给客户端,不用经过网络端。

Connect;为当前的请求找到一个合适的链接,有可能复用已有的链接,如果链接可以复用就不用重新创建,还涉及到连接池的概念

CallServer:向服务器发起真的网络请求然后返回

public void synRequest(){

    OkHttpClient client =

new               OkHttpClient.Builder().connectTimeout(60,TimeUnit.SECONDS).build();

    Request request =

new Request.Builder().url("http://www.baidu.com").get().build();

    Call call = client.newCall(request);

try {

        Response response =call.execute();

        System.

out.print(response.body().string());

    }

catch (IOExceptione) {

        e.printStackTrace();

    }

}

接下来我们分析OkHttpClient.Builder()内部类

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;

}

从内部类的构造方法中可以看出创建了Dispatcher,ConnectionPool两个重要的类

接下来我们分析Request的创建

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 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".

     *

     *

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主要是一些请求前的信息设置如url,请求方式,请求头等的设置

接下来我们分析

Callcall = client.newCall(request);

Call是链接request和response的桥梁

Okhttpclient类中

@Override public Call newCall(Request request) {

return RealCall.newRealCall(this, request, false /* for web socket */);

}

RealCall类中

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;

}

主要是创建RealCall

接下来我们分析

Response response = call.execute();

RealCall类中

@Override public Response execute() throws IOException {

synchronized (this) {

//保证每个call只能执行一次

    if (executed) throw new IllegalStateException("Already Executed");

executed = true;

  }

  captureCallStackTrace();

eventListener.callStart(this);

try {

client.dispatcher().executed(this);

//通过连接器连里面的拦截器依次执行

    Response result = getResponseWithInterceptorChain();

    if (result == null) throw new IOException("Canceled");

return result;

  }

catch (IOException e) {

eventListener.callFailed(this, e);

throw e;

  }

finally {

client.dispatcher().finished(this);

  }

}

[if !supportLineBreakNewLine]

[endif]

我们分析

client.dispatcher().executed(this);

Dispatcher类中

private final Deque runningSyncCalls = new ArrayDeque<>();

/** Used by {@code Call#execute} to signal it is in-flight. */

synchronized void executed(RealCall call) {

runningSyncCalls.add(call);

}

我们从中可以看出同步请求就是将call添加到同步队列中

接下来我们分析

client.dispatcher().finished(this);

private void finished(Deque calls, T call, boolean promoteCalls) {

int runningCallsCount;

  Runnable idleCallback;

synchronized (this) {

if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");

if (promoteCalls) promoteCalls();

    runningCallsCount = runningCallsCount();

    idleCallback =

this.idleCallback;

  }

if (runningCallsCount == 0 && idleCallback != null) {

    idleCallback.run();

  }

}

public synchronized int runningCallsCount() {

return runningAsyncCalls.size() + runningSyncCalls.size();

}

从中我们可以看出主要是重新计算请求的数量

接下来我们分析RealCall中

Response result = getResponseWithInterceptorChain();

Response getResponseWithInterceptorChain() throws IOException {

// Build a full stack of interceptors.

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

}

主要是依次执行拦截器连中不同功能的拦截器来获取数据,后续的章节我们会介绍每个拦截器的作用。

上一篇下一篇

猜你喜欢

热点阅读