OkHttp请求过程以及拦截器原理

首先来看看OkHttp的基础,异步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构造方法

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(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  ...
  
 }

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

创建请求

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

发起请求

Response response = client.newCall(request).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);
    }
  }

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

其实可以看出来,这个方法主要就是添加各种interceptor,然后文章最开始提到的第一个interceptors其实是自定义的拦截器,添加到了最前面,然后依次添加了四种拦截器过后,第五个是networkInterceptors,最后一共加了七种拦截器

拦截器责任链

责任链模式

  public RealInterceptorChain(List interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
      EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
    this.call = call;
    this.eventListener = eventListener;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }

这里主要是初始化了各种属性,这里面的参数大多数和OkHttp的属性无异,但需要注意的是这里的interceptors不同于OkHttp构造里面的那个interceptors,这里是表示刚才组成的所有拦截器的数组,包含interceptors和networkInterceptors在内的七种拦截器,然后index这个属性初始化为“0”。
接下来在getResponseWithInterceptorChain最后一句执行了它的proceed方法,在这个方法里有很多抛出异常的语句,这里不去深究,主要看看中间主要的一两句:
RealInterceptorChain.proceed

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

     ... ...

    // 重点!!!主要就看看这几句
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    ... ...

    return response;
  }

划重点!在这里就到了最核心的几句了
首先:又实例化了一个RealInterceptorChain,取名为next(从名字真的可以看出很多蹊跷),构造参数没变化,只是把index+1;
然后:从interceptors数组中用index来依次取出Interceptor(每次执行index都会+1,所以是依次取出来);
最后:调用interceptor.intercept(next),把next传入调用intercept方法

intercept(Chain chain)

@Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    
    response = realChain.proceed(request, streamAllocation, null, null);
}

这个方法里面会对一些参数做修改,又调用了proceed方法,在proceed方法里我们知道index又会+1,然后取出下一个拦截器并且传入修改后的参数。这就完成了这个链式结构的运转,一步一步的往下传递,然后到了最后又依次返回Response

各种拦截器

RetryAndFollowUpInterceptor

用来实现连接失败的重试和重定向

BridgeInterceptor
用来修改请求和响应的 header 信息

CacheInterceptor
用来实现响应缓存。比如获取到的 Response 带有 Date,Expires,Last-Modified,Etag 等 header,表示该 Response 可以缓存一定的时间,下次请求就可以不需要发往服务端,直接拿缓存的

ConnectInterceptor

用来打开到服务端的连接。其实是调用了 StreamAllocation 的newStream 方法来打开连接的。建联的 TCP 握手,TLS 握手都发生该阶段。过了这个阶段,和服务端的 socket 连接打通

interceptors和networkInterceptors分别位于拦截器链的第一个和第六个,从每个拦截器的作用大致猜到一些。interceptors是肯定每次都会执行的,但是,在networkInterceptors之前有个ConnectInterceptor,这个拦截器的作用是用于建立跟服务器的连接。那如果我们现在设备离线,直接读取缓存呢?对,那这样的话networkInterceptors就不会执行了。

你可能感兴趣的:(OkHttp请求过程以及拦截器原理)