Android开发Android开发经验谈Android技术知识

OkHttp源码解析

2020-09-10  本文已影响0人  奔跑吧李博

Okhttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由大名鼎鼎的Square公司贡献。

使用方式

引入库:
 implementation 'com.squareup.okhttp3:okhttp:3.2.0'  
发起get请求:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        Request request = new Request.Builder()
                .url("")
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
发起post请求:
       RequestBody requestBody = new FormBody.Builder()
                .add("","")
                .build();

        Request request = new Request.Builder()
                .url("")
                .addHeader("","")
                .post(requestBody)
                .build();

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        try {
            Response response = okHttpClient.newCall(request).execute();
            response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
okhttp内部封装功能:
final Dispatcher dispatcher;
  final Proxy proxy;
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;
  final List<Interceptor> networkInterceptors;
  final ProxySelector proxySelector;
  final CookieJar cookieJar;
  final Cache cache;
  final InternalCache internalCache;
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;
  final TrustRootIndex trustRootIndex;
  final HostnameVerifier hostnameVerifier;
  final CertificatePinner certificatePinner;
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  final ConnectionPool connectionPool;
  final Dns dns;
  final boolean followSslRedirects;
  final boolean followRedirects;
  final boolean retryOnConnectionFailure;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
属性解释:
OkHttp流程图:
流程解析
创建OkhttpClient
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

官方建议使用单例创建OkHttpClient,即一个进程中只创建一次即可,以后的每次交易都使用该实例发送交易。这是因为OkHttpClient拥有自己的连接池和线程池,这些连接池和线程池可以重复使用,这样做利于减少延迟和节省内存,如果咱们每次发交易都创建一个OkHttpClient的话,将会浪费很多内存资源。

创建Call对象
        val request = Request.Builder()
            .url("")
            .build()

        okHttpClient.newCall(request)

一个Call对象表示一次请求,每一次请求都会生成一个新的Call,Call其实是一个接口,它的具体实现类是RealCall。

  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }
RealCall构造方法:
  protected RealCall(OkHttpClient client, Request originalRequest) {
    this.client = client;
    this.originalRequest = originalRequest;
  }

创建Call对象时候传进去了一个Request对象,Request对象表示用户的请求参数,并传入OkHttpClient对象。

Request类部分代码:
public final class Request {
  private final HttpUrl url;  //请求url
  private final String method;  //请求的get/post/put/delete方式
  private final Headers headers;  //请求头
  private final RequestBody body;  //请求体
  private final Object tag;

  private volatile URI javaNetUri; // Lazily initialized.
  private volatile CacheControl cacheControl; // Lazily initialized.

  private 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;
  }
}
执行请求

okhttp3中提供了两种请求方式:一种是同步请求,第二种是异步请求。同步请求调用call.execute()方法,异步请求调用call.enqueue(Callback callback)方法。

public interface Call {

 /**立即调用请求,并阻塞,直到响应可以被处理或进入*/
  Response execute() throws IOException;

  /**
   * 计划在将来某个时间执行的请求
   */
  void enqueue(Callback responseCallback);
}
RealCall中实现:

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

  @Override public void enqueue(Callback responseCallback) {
    enqueue(responseCallback, false);
  }

  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

执行请求最终是通过Dispatcher类来调用,Dispatcher是okhttp3的任务调度核心类,负责管理同步和异步的请求,管理每一个请求任务的请求状态,并且其内部维护了一个线程池用于执行相应的请求。

Dispatcher类部分代码:
public final class Dispatcher {
  /** 用于保存等待执行的异步队列 */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 用于保存正在执行的异步队列 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
}

 //调度器Dispatcher内部维护了一个ThreadPoolExecutor线程池,并直接将call对象传入线程池执行。
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
   
  //同步执行
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }
  
  //异步执行
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

可以这么理解:把Dispatcher当成生产者,把线程池当成消费者,如果生产的线程小于可消费的范围,则立即加入消费队列;而当生产者生产的线程大于消费者所能承受的最大范围,就把未能及时执行的任务保存在readyAsyncCalls队列中,当时机成熟,也就是线程池有空余线程可以执行时,会调用promoteCall()这个方法把等待队列中的任务取出放到线程池中执行,并且把这个任务转移到runningAsyncCalls队列中去。

拦截器链

通过上面的分析咱们知道不管是同步请求还是异步请求,最后都会走getResponseWithInterceptorChain()方法,getResponseWithInterceptorChain()是okhttp3中的精髓设计之一。

Response response = getResponseWithInterceptorChain(forWebSocket);

具体实现过程:

  private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

  class ApplicationInterceptorChain implements Interceptor.Chain {
    private final int index;
    private final Request request;
    private final boolean forWebSocket;

    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
      this.index = index;
      this.request = request;
      this.forWebSocket = forWebSocket;
    }

    @Override public Connection connection() {
      return null;
    }

    @Override public Request request() {
      return request;
    }

    @Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      return getResponse(request, forWebSocket);
    }
  }

获取okhttpClient中设置的各个intercepter拦截器,通过拦截器链对请求数据和返回数据进行处理,内部采用责任链模式,将每一个拦截器对应负责的处理任务进行严格分配,最后将交易结果返回并回调到暴露给调用者的接口上。

参考文章
okhttp3源码分析:架构全面解析

上一篇下一篇

猜你喜欢

热点阅读