okhttp执行与拦截器

本文使用okhttp3源码来讲解

1、同步和异步的区别

(1)同步方法execute()

okHttpBuilder.build().newCall()会创建一个RealCall对象

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

然后看下RealCall的execute()方法

//RealCall.java
@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); //执行结束后从双向链表移除
  }
}

(2)异步方法enqueue

异步方法enqueue也位于RealCall.java中,具体实现如下

//RealCall.java
@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));//异步执行
}

创建了一个AsyncCall对象,并将回调接口作为参数。AsyncCall继承于抽象类NamedRunnable,NamedRunnable又继承自Runnable接口,所以这里新开了一个线程去执行execute()方法。

//NamedRunnable.java
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();//子线程执行
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}
//RealCall.java
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() { //继承自父类,并在子线程run方法中被调用
    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);
    }
  }
}

看下client.dispatcher().enqueue做了啥

//Dispatcher.java
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}

enqueue将任务添加到双端链表中,这里有两个队列-任务队列和等待队列,当并发任务数大于64或者相同域名数量大于5个时就加入到等待队列

2、拦截器种类和顺序

使用okhttp进行网络请求时不管是不同请求(execute())还是异步请求(enqueue(Callback responseCallback))都会走到getResponseWithInterceptorChain()方法来添加拦截器。

//RealCall.java
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()); //第5个参数index=0要注意,后面分析会用到

  return chain.proceed(originalRequest);
}

 根据代码可以看到拦截器添加的顺序依次为client.interceptors()、retryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、networkInterceptors、CallServerInterceptor,由于是ArrayList容器所以可以保证顺序。

看下拦截链的proceed方法,可以看到根据index参数以及RealInterceptorChain,每个拦截器都会执行其intercept方法,在intercept方法中会通过执行后续拦截链的proceed方法,这样就逐步执行了拦截连上的所有拦截器

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
    RealConnection connection) throws IOException {
  if (index >= interceptors.size()) throw new AssertionError(); //初始时index 是上面传入的第五个参数0

  calls++;

  // If we already have a stream, confirm that the incoming request will use it.
  if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
    throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
        + " must retain the same host and port");
  }

  // If we already have a stream, confirm that this is the only call to chain.proceed().
  if (this.httpCodec != null && calls > 1) {
    throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
        + " must call proceed() exactly once");
  }

  // Call the next interceptor in the chain.
  RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
      connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
      writeTimeout); //从下个拦截器开始的拦截链,初始时由于index是0,则index+1等于1,相当于下一个拦截器的index就变为了1,一次类推index逐步增加
  Interceptor interceptor = interceptors.get(index);//当前拦截器
  Response response = interceptor.intercept(next);//以新的拦截链为参数,执行当前拦截器的intercept方法,这样就一次执行了拦截链上的每个拦截器

  // Confirm that the next interceptor made its required call to chain.proceed().
  if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
    throw new IllegalStateException("network interceptor " + interceptor
        + " must call proceed() exactly once");
  }

  // Confirm that the intercepted response isn't null.
  if (response == null) {
    throw new NullPointerException("interceptor " + interceptor + " returned null");
  }

  if (response.body() == null) {
    throw new IllegalStateException(
        "interceptor " + interceptor + " returned a response with no body");
  }

  return response;
}

网上盗个图说下拦截器流程

猜你喜欢

转载自blog.csdn.net/u013795543/article/details/114990284