okhttp源码分析

一、okhttp简介

OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。现在在Android开发中最火的应用最多的联网框架毫无疑问是okhttp,目前已经大量替代了Volley、HttpUrlConnection。

二、okhttp用法
1)导包:

    compile 'com.squareup.okhttp3:okhttp:3.9.1'

2)通过Builder类实例化客户端类OkhttpClient。

 private val client: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(60, TimeUnit.SECONDS)
            .build()
    }

实例化OkhttpClient时可以通过Builder类添加一系列客户端参数。
3)通过Builder类实例化请求类Request,通过OkHttpClient的newCall方法执行请求。

 fun get(url: String, callBack: ResponseCallBack) {
        var request = Request.Builder()
            .url(Api.baseUrl + url)
            .build()
        client.newCall(request).enqueue(
            object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    callBack?.onFail(e.toString())
                }

                override fun onResponse(call: Call, response: Response) {
                    callBack?.onSuccess(response.body()!!.string())
                }

            }
        )
    }

    fun post(url: String, requestParams: RequestParams, callBack: ResponseCallBack) {
        var requestBody = FormBody.Builder()
        requestParams.forEach {
            requestBody.add(it.key, it.value.toString())
        }
        var request = Request.Builder()
            .url(Api.baseUrl + url)
            .post(requestBody.build())
            .build()
        client.newCall(request).enqueue(
            object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    callBack?.onFail(e.toString())
                }

                override fun onResponse(call: Call, response: Response) {
                    callBack?.onSuccess(response.body()!!.string())
                }
            }
        )
    }

实例化Request时可以通过Builder类添加一系列请求参数(例如Header信息),这里也不进行详细描述,在分析源码时进行具体分析。
4)同步、异步请求。execute()执行同步请求,enqueue()执行异步请求,同步请求方法返回Response,异步请求通过CallBack返回Response。

三、源码分析
1)OkHttpClient客户端类,主要看一下各个成员变量。

final Dispatcher dispatcher;//请求分发器,分发执行Request
  final @Nullable Proxy proxy;//代理
  final List protocols;//协议,管理协议版本
  final List connectionSpecs;//传输层版本和连接协议
  final List interceptors;//拦截器
  final List networkInterceptors;//网络拦截器
  final EventListener.Factory eventListenerFactory;//请求监听器
  final ProxySelector proxySelector;//代理选择
  final CookieJar cookieJar;//cookie
  final @Nullable Cache cache;//缓存
  final @Nullable InternalCache internalCache;//内部缓存
  final SocketFactory socketFactory;//socket工厂
  final @Nullable SSLSocketFactory sslSocketFactory;//HTTPS ssl安全套接层工厂
  final @Nullable CertificateChainCleaner certificateChainCleaner;//验证证书
  final HostnameVerifier hostnameVerifier;//确认主机名
  final CertificatePinner certificatePinner;//证书链
  final Authenticator proxyAuthenticator;//代理身份验证
  final Authenticator authenticator;//本地身份验证
  final ConnectionPool connectionPool;//连接池
  final Dns dns;//DNS域名解析
  final boolean followSslRedirects;//安全套接层重定向
  final boolean followRedirects;//本地重定向
  final boolean retryOnConnectionFailure;//连接失败重试
  final int connectTimeout;//连接超时
  final int readTimeout;//读取超时
  final int writeTimeout;//写入超时
  final int pingInterval;//ping命令时间间隔

可以看到所有成员变量都是final的,这样所有的变量赋值就全部交给Builder类,Builder类是OkHttpClient的静态内部类。可以通过builder()来完成设置,在不进行设置情况下会使用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;
    }

2)Request请求信息类。成员变量如下:

  final HttpUrl url;//请求url信息
  final String method;//请求方式(post get)
  final Headers headers;//请求header
  final @Nullable RequestBody body;//请求Body
  final Object tag;//请求tag

3)执行newCall()方法创建Call对象,Call接口唯一实现类是RealCall,是执行请求的真正对象。

  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
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请求类的源码如下:

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;//请求重定向拦截器
  private EventListener eventListener;
  final Request originalRequest;//request信息
  final boolean forWebSocket;
  // Guarded by this.
  private boolean executed;
  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  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;
  }
  //同步请求
  @Override public Response execute() throws IOException {
    synchronized (this) {
      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);
    }
  }
.....
//异步请求
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

  @Override public void cancel() {
    retryAndFollowUpInterceptor.cancel();
  }

  @Override public synchronized boolean isExecuted() {
    return executed;
  }

  @Override public boolean isCanceled() {
    return retryAndFollowUpInterceptor.isCanceled();
  }

  @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
  @Override public RealCall clone() {
    return RealCall.newRealCall(client, originalRequest, forWebSocket);
  }

  StreamAllocation streamAllocation() {
    return retryAndFollowUpInterceptor.streamAllocation();
  }

  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();
        if (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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

//链式请求方法
  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);
  }

先来分析同步请求,从源码中可以看到同步请求中会先通过

client.dispatcher().executed(this);

完成对请求的监听,本质上是将当前请求放入一个队列中,当请求结束之后再移除队列。

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque runningSyncCalls = new ArrayDeque<>();

对于异步请求来说同样会进行请求的监听,唯一的区别在于异步请求是用两个队列完成,一个是等待请求的队列,一个是正在请求的队列。

/** Ready async calls in the order they'll be run. */
  private final Deque readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque runningAsyncCalls = new ArrayDeque<>();

最终进行网络请求是通过链式方法getResponseWithInterceptorChain来完成的。这个方法也是网络请求的精髓所在。这个方法里通过获取设置的一系列拦截器来完成网络请求工作,每个拦截器有不同的分工。最后通过构建的拦截器链调用proceed()方法完成网络请求。由于不同的拦截器分别负责网络请求中的不同工作。分析起来内容比较多,这里先不进行具体各个拦截器的源码分析。

4)Dispatcher请求分发器,在okhttp中网络请求分发是通过Dispatcher分发器来维护的,Dispatcher控制着当前网络请求是否执行还是进入等待状态,这里涉及一些网络请求的域名等判断信息。Dispatcher类源码如下:

public final class Dispatcher {
  private int maxRequests = 64;//最大请求数
  private int maxRequestsPerHost = 5;//最大主机名
  private @Nullable Runnable idleCallback;
  private @Nullable ExecutorService executorService;//请求线程池,核心线程0,非核心线程最大值Integer.MAX_VALUE
  private final Deque readyAsyncCalls = new ArrayDeque<>();//异步等待队列
  private final Deque runningAsyncCalls = new ArrayDeque<>();//异步请求队列
  private final Deque runningSyncCalls = new ArrayDeque<>();//同步请求队列
.......
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

  public synchronized void setMaxRequests(int maxRequests) {
    if (maxRequests < 1) {
      throw new IllegalArgumentException("max < 1: " + maxRequests);
    }
    this.maxRequests = maxRequests;
    promoteCalls();
  }

  public synchronized int getMaxRequests() {
    return maxRequests;
  }
  public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
    if (maxRequestsPerHost < 1) {
      throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
    }
    this.maxRequestsPerHost = maxRequestsPerHost;
    promoteCalls();
  }

  public synchronized int getMaxRequestsPerHost() {
    return maxRequestsPerHost;
  }

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

  private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

  private int runningCallsForHost(AsyncCall call) {
    int result = 0;
    for (AsyncCall c : runningAsyncCalls) {
      if (c.host().equals(call.host())) result++;
    }
    return result;
  }

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

  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

  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 List runningCalls() {
    List result = new ArrayList<>();
    result.addAll(runningSyncCalls);
    for (AsyncCall asyncCall : runningAsyncCalls) {
      result.add(asyncCall.get());
    }
    return Collections.unmodifiableList(result);
  }
  public synchronized int queuedCallsCount() {
    return readyAsyncCalls.size();
  }
  public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }
}

在同步请求时直接加入同步请求队列中,持有同步请求的请求引用。对于异步请求来讲,会判断当前正在执行的请求是否达到最大请求限制,并且正在执行请求的主机名是否达到个数限制,如果都没有达到限制,则立即通过线程池进行网络请求,否则放入异步等待队列。那么什么时候进行执行等待队列中的请求呢?
在一个网络请求结束之后会调用Dispatcher的finished方法,在finished方法中会调用promoteCalls()方法来判断时候可以执行等待队列中的网络请求。

文中demo代码:https://github.com/24KWYL/okhttp.git

你可能感兴趣的:(okhttp源码分析)