Okhttp同步Get分析

Okhttp同步Get分析_第1张图片
Okhttp同步Get分析_第2张图片


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

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

}

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

你可能感兴趣的:(Okhttp同步Get分析)