解析OKHttp

先看一下平常我们是如和使用okHttp的 下面是官网上例子

OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  Response response = client.newCall(request).execute();
  return response.body().string();
}

总共分三部,下面咱们排着个解析一下

第一步

OkHttpClient client = new OkHttpClient();

来看一下这个okHttpClient这个类是干吗的

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

在new OkHttpClient的时候 其实是创建了一个 Build对象,(Build模式,Build是一个内部类,常用于先对Build类进行赋值,最后再生成主类)

来看一下Build类

//OkHttpClient类
public static final class Builder {
    Dispatcher dispatcher;//任务调度类
    @Nullable Proxy proxy;//代理类
    List<Protocol> protocols;//协议类集合
    List<ConnectionSpec> connectionSpecs;//连接规格集合
    final List<Interceptor> interceptors = new ArrayList<>();//拦截器集合
    final List<Interceptor> networkInterceptors = new ArrayList<>();//网络拦截器
    EventListener.Factory eventListenerFactory;//事件监听工厂类
    ProxySelector proxySelector;
    CookieJar cookieJar;
    @Nullable Cache cache;
    @Nullable InternalCache internalCache;
    SocketFactory socketFactory;
    @Nullable SSLSocketFactory sslSocketFactory;
    @Nullable CertificateChainCleaner certificateChainCleaner;
    HostnameVerifier hostnameVerifier;
    CertificatePinner certificatePinner;
    Authenticator proxyAuthenticator;
    Authenticator authenticator;
    ConnectionPool connectionPool;//连接池
    Dns dns;
    boolean followSslRedirects;
    boolean followRedirects;
    boolean retryOnConnectionFailure;
    int connectTimeout;//连接时间
    int readTimeout;//读取时间
    int writeTimeout;//等待时间
    int pingInterval;

    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(OkHttpClient okHttpClient) {
      this.dispatcher = okHttpClient.dispatcher;
      this.proxy = okHttpClient.proxy;
      this.protocols = okHttpClient.protocols;
      this.connectionSpecs = okHttpClient.connectionSpecs;
      this.interceptors.addAll(okHttpClient.interceptors);
      this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
      this.eventListenerFactory = okHttpClient.eventListenerFactory;
      this.proxySelector = okHttpClient.proxySelector;
      this.cookieJar = okHttpClient.cookieJar;
      this.internalCache = okHttpClient.internalCache;
      this.cache = okHttpClient.cache;
      this.socketFactory = okHttpClient.socketFactory;
      this.sslSocketFactory = okHttpClient.sslSocketFactory;
      this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
      this.hostnameVerifier = okHttpClient.hostnameVerifier;
      this.certificatePinner = okHttpClient.certificatePinner;
      this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
      this.authenticator = okHttpClient.authenticator;
      this.connectionPool = okHttpClient.connectionPool;
      this.dns = okHttpClient.dns;
      this.followSslRedirects = okHttpClient.followSslRedirects;
      this.followRedirects = okHttpClient.followRedirects;
      this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
      this.connectTimeout = okHttpClient.connectTimeout;
      this.readTimeout = okHttpClient.readTimeout;
      this.writeTimeout = okHttpClient.writeTimeout;
      this.pingInterval = okHttpClient.pingInterval;
    }
看起来很多 其实就是给属性赋值而已,

Builder()构造方法 是自己给属性赋值,

Builder(OkHttpClient okHttpClient)是利用OkHttpClient 对象来赋值我们重点看参数,重要的我已经写注解了,直接看属性

可以看出OkHttpClient类 是对请求的一个封装类,

dispatch和interrupt很重要 下面会讲到

接下来看第二步

 Request request = new Request.Builder()
                    .url(url)
                    .build();

我们来看Requet类

//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;
  }

很明显 这个类 是一个请求的类,包含了请求地址,请求头,请求方式

接下来看第三步

 Response response = client.newCall(request).execute();

这时候 我们有了执行请求的OkHttpClient类,有了封装请求的Request类,我们就要开始执行请求了,

有两个方法 我们分别来看一下,newCall和execut,

newCall:

//OKHttpClient类 
@Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
可以看出 返回了一个RealCall,来看一下RealCall这个类
//RealCall类
final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /**
   * There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward.
   * This will be set after we create the call instance then create the event listener instance.
   */
  private 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;

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


可以看出 realCall实现了call接口,并且这个类持有 OkHttpCall和Requset ,

那么在执行okHttpClient.newCall(request). execute/enqueue的时候 其实是执行了RealCall类的execute/enqueue

接下来我们详细看一下OkHttpClent的dispatch

//dispatch类
public final class Dispatcher {
  private int maxRequests = 64;//最大并发请求数量
  private int maxRequestsPerHost = 5;//每个主机的最大请求数
  private @Nullable Runnable idleCallback;//貌似是回掉类

  /** Executes calls. Created lazily. */
  private @Nullable ExecutorService executorService;//线程池

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//将要运行的异步队列

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在运行的异步队列

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//正在运行同步队列

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }
//在这一步可以看出来executeService其实就是一个线程池
 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;
  }

可以看出 dispatch是执行请求的封装类,

接下来我们看一下他是如和进行请求的,

好 现在我们先捋一下吧还是,

我们首先我们创建了Okhttpclient (里面有一个dispatch和executeService)和 request,

我们在调用OKHttpClient。newCall(request)的时候

其实是new出来一个一个RealCall,RealCall实现了Call接口,

在执行RealCall.execute/enqueue的时候,其实是将RealCall给了dispatch,

dispatch将realCall传给了executeService,

至此 我们已经将请求添加到线程池里了,那么我们是在什么时候执行呢

分两种情况 一种是同步请求 一种是异步请求,

先看同步的吧

 
//RealCall类
@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);//将请求在队列中移除
    }
  }
看一下dispatch的executed
//dispatch类
/** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }
其实就是将请求添加到正在运行的同步队列中

我们来看一下getResponseWithInterruptorChain,
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
//创建一个拦截器集合
     List<Interceptor> interceptors = new ArrayList<>();
//假如OKHttpClient中的拦截器,我们自己定义的拦截器也是在这个时候添加的
 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);
  }


看一下dispatch的finished方法
void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");//注释1
      if (promoteCalls) promoteCalls();//注释2
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }
    //runingCallsCount是正在运行的请求数量
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }
看注1处 将当前请求移除队列,因为promoteCalls是false 所以并不会执行promoteCalls,不过这个方法很重要,下面会讲到,

同步的分析完了 我们看一下异步的,同样 也是从realCall的enqueue开始
//realcall类
 @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));//最终也是执行了dispatch的enqeue
  }
套路是一样的,看dispatch的enqueue
//dispatch类 
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
和同步不一样的地方是 同步是RealCall异步是AsyncCall(是RealCall的一个内部类)
executeService>execute(Call)这里其实是执行的call的execute方法,
我们来看一下
//AsyncCall类 
 @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);//重点还有这里
      }
    }
虽然说异步call是AsyncCall 但是执行请求和将请求移除队列 还是用的RealCall里的方法
getResponseWithInterceptorChain刚刚已经解释过了 其实就是执行请求 并得到返回的结果

我们把重点放到clinet.dispatcher.finished(this);上来
//dispatch类
void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }
//dispatch类
private <T> void finished(Deque<T> 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();//这个是promoteCalls为true
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }
移除当前的请求,
这个时候promoteCalls为true,所以会执行promoteCalls

//dispatch类 
 private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> 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.
    }
  }
可以看出,如果异步队列中还有任务 则调用executeService.execut(call)来执行下一个任务

好了 大致就是这样,





























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值