OkHttp3.9请求过程源码解析

首先来看看OkHttp的基础

创建一个普通的同步get请求代码如下:

OkHttpClient client = new OkHttpClient();//1
String run(String url) throws IOException {
    Request request = new Request.Builder().url(url).build();//2
    Response response = client.newCall(request).execute();//3
    if (response.isSuccessful()) {
        return response.body().string();
    } else {
        throw new IOException("Unexpected code " + response);
    }
}

异步get:

OkHttpClient client = new OkHttpClient();//1
    Request request = new Request.Builder()
            .url("http://xxxxxx")
            .build();//2
    client.newCall(request).enqueue(new Callback() {//3
        @Override
        public void onFailure(Call call, IOException e) {
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if(response.isSuccessful()){//回调的方法执行在子线程。
                
            }
        }
    });

都是主要三个步骤:1.创建OkHttpClient实例;2.使用构造器创建请求;3.提交请求。

OkHttpClient构造方法

从构造方法开始,看看OkHttpClient的创建过程

public OkHttpClient() {
    this(new Builder());
  }
public Builder() {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;//代理
    this.protocols = builder.protocols;//协议
    this.connectionSpecs = builder.connectionSpecs;//策略
    this.interceptors = Util.immutableList(builder.interceptors);//拦截器
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);//网络拦截器
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
}

可以看到,创建的过程主要是调用了构造器的构造方法,初始化了一些请求相关的参数,这里面几乎都是跟HTTP请求相关的参数,就不深入去追究,主要是要注意这里有三个东西:就是interceptors和networkInterceptors(这两个类就是这篇文章的主题,后面再细说),还有一个Dispatcher,我们需要进去看看,在这里我们可以知道OkHttp请求的任务调度原理:

public final class Dispatcher {
  private int maxRequests = 64;//最大请求任务个数
  private int maxRequestsPerHost = 5;//最大允许同一host的请求任务个数
  
  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

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

可以看出来,Dispatcher就像是一个调度中心,这里负责所有的任务执行,值得注意的是我们看到executorService这个对象是个线程池,而且是个不限制大小的线程池,这里用到了SynchronousQueue(没有缓存大小的阻塞队列),这个线程池跟Executors默认的newCachedThreadPool原理相同,当任务加入时如果有空闲的线程就复用,没有的话就创建新的线程,每个线程空闲后60秒被销毁。

创建请求

Request request = new Request.Builder()
            .url("http://xxxxxx")
            .build();

这一步很简单,传入请求地址就OK,也没什么多说的

发起请求

到这里算是到了正文,来看看OkHttp的请求到底是怎么来执行的,先看同步的请求:

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

client.newCall(request):

  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

调用RealCall.newRealCall:

  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的构造:

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

在这里除了初始化一些对象以外,还有一个很重要的东西,RetryAndFollowUpInterceptor,又看到了一个Interceptor,还记得我们在前面OkHttp的构造中也有一个interceptors和networkInterceptors,看名字也知道他们肯定有什么关系,具体是什么关系我们先买一个伏笔,继续往下看RealCall的同步网络请求execute方法:

RealCall.execute

  @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);//1
      Response result = getResponseWithInterceptorChain();//2
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

到这里,一次同步请求就执行完毕了,不得不感叹OkHttp设计者的强大,API的调用简单明了不说,竟然源码也这么一气呵成。好了,来看看具体是怎么处理的,核心代码在try代码块里面的两行

1. client.dispatcher().executed(this)

这里的dispatcher()也就是之前着重讲到的那个调度器,来看看它的executed方法:

Dispatcher.executed

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

很简单一句,往运行时队列里面加入这个请求,再顺便看看这个队列吧

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

注释都写的很清楚,就不翻译了

2. Response result = getResponseWithInterceptorChain();

这里又看到了Interceptor相关的东西,到了这里,箭在弦上,不得不发了,终于可以引出OkHttp最核心的拦截器机制了。

Interceptor

先来看看拦截器的定义:

Java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。
在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。

在OkHttp中,拦截器就是在请求的各个阶段进行一些处理,然后再传递下去继续执行。那OkHttp的拦截器到底是怎么一回事,先回到刚才的那个getResponseWithInterceptorChain方法看看:

RealCall.getResponseWithInterceptorChain

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> 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);
  }

题目揭晓

在这里看到了,interceptors其实是一个数组,在OkHttp构造里面也初始化了这个数组和networkInterceptors,那这两个数组到底有什么区别呢?感觉篇幅有点多了,下一篇我们来解开它的答案

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值