okhttp3请求流程源码分析

okhttp3现在是我们常用的一个网络请求框架,面试的时候也会问一些相关的问题,之前看了一阵源码,现在写出来看源码总结的一些知识点当作自己的收获。主要是看post请求相关流程。

        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody requestBody = new FormBody.Builder()
                .add("username", "sssss")
                .add("password", "111111")
                .build();
        Request request = new Request.Builder()
                .url("https://www.wanandroid.com/user/login")
                .post(requestBody)
                .build();

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("okhttp", "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Log.d("okhttp", "onResponse: " + response.body().string());
            }
        });

这是我们建立一个post请求的时候常用的使用方式。首先看OkHttpClient这个类

  public OkHttpClient() {
    this(new 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;
    }

可以看到,我们在使用okhttpclient的时候,做了一些初始化的工作。这些参数都是做网络请求服务的。

        RequestBody requestBody = new FormBody.Builder()
                .add("username", "sssss")
                .add("password", "111111")
                .build();
        Request request = new Request.Builder()
                .url("https://www.wanandroid.com/user/login")
                .post(requestBody)
                .build();
    public FormBody build() {
      return new FormBody(names, values);
    }

    FormBody(List<String> encodedNames, List<String> encodedValues) {
    this.encodedNames = Util.immutableList(encodedNames);
    this.encodedValues = Util.immutableList(encodedValues);
  }
    public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }


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

上面的就是为了构建出请求体和请求request,这些都没什么好说的,都是作为http请求的一个必要参数。

 okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("okhttp", "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                Log.d("okhttp", "onResponse: " + response.body().string());
            }
        });

真正的重头戏开始了,这才是真正开始发送请求到返回结果,处理结果的过程,其中一些列的流程是比较清晰的,下面我们追踪一下源码流程。首先我们先看一下newCall这个方法干了什么

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @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;
  }

其实就是构建出一个call对象,来执行enqueue()方法。

  @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));//最终执行的步骤
  }

最终我们看见进入了client.dispatcher().enqueue(new AsyncCall(responseCallback));这个client.dispatcher是在Realcall的构造方法当中进行的赋值,将初始化的okhttpclient赋值。dispatcher实在okhttpClient的构造方法当中创建的对象,所以说最终执行的就是Dispatcher的enqueue方法。这个Dispatcher是okhttp中一个比较重要的类,首先我们先看它的成员

  /** 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<>();

这三个成员可以看出来是三个队列,这三个队列也是Dispatcher所掌控的我们日常使用的一个请求队列。

  1. readyAsyncCalls :是异步请求的准备队列
  2. runningAsyncCalls 是异步请求的执行队列
  3. runningSyncCalls 是同步请求的执行队列

当我们知道这三个队列之后,我们看enqueue方法

  
  private int maxRequests = 64;//最大请求数
  private int maxRequestsPerHost = 5;//最大请求同一ip的并发数

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

Dispiatcher会根据条件判断,这么逻辑比较简单,就不仔细说了,如果符合条件,就会异步请求执行队列中,然后执行 executorService().execute(call);不符合条件就加入到异步请求准备队列中。

  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;
  }
public interface ExecutorService extends Executor {
    ...
}


public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

我们不难看出最终的execute方法传入的是一个Runable对象,那么我们这个enqueue(AsyncCall call)这个AsyncCall是什么呢?

 final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

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

其实就是Runable的实现类,那么最终执行的其实就是AsyncCall 当中的execute方法。AsyncCall是RealCall的内部类,所以我们去看AsyncCall的execute方法,

@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);//请求结束
      }
    }
  }

我们先看流程,当请求最终执行execute方法的时候,首先会经历 getResponseWithInterceptorChain()这个方法返回response对象,然后会经过逻辑判断,是执行成功还是失败的回调,最终都会由Dispatcher类执行结束。由此可见,Dispatcher这个类管理了请求队列,发送请求,结束请求,由名字可以看出,它是分发器类,它干的活也是这个,我只管维护请求队列的开始,结束,我不管期间你做了什么,返回什么response。这个类也是okhttp的一个重点。好,下面我们看一下 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) {//判断是否是webSocket连接
      interceptors.addAll(client.networkInterceptors());//将用户自定义的网络拦截器加入集合中
  
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));//将CallServerInterceptor加入集合中

    //创建拦截器链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    //调用了RealInterceptorChain的proceed方法,返回response
    return chain.proceed(originalRequest);
  }

代码量非常少,但是逻辑比较清晰,然后我们看看Interceptor和 Interceptor.Chain

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    @Nullable Connection connection();

    Call call();

    int connectTimeoutMillis();

    Chain withConnectTimeout(int timeout, TimeUnit unit);

    int readTimeoutMillis();

    Chain withReadTimeout(int timeout, TimeUnit unit);

    int writeTimeoutMillis();

    Chain withWriteTimeout(int timeout, TimeUnit unit);
  }
}

Interceptor.Chain可以看出是一个接口,它其实也是okhttp请求的一个核心,拦截器链,它有自己的实现类RealInterceptorChain

  public RealInterceptorChain(List<Interceptor> 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;
  }

这里就是实现类的构造方法,那好,现在我们先缕一缕:

  1. 首先创建okhttpClient对象,然后创建请求体,创建request,然后通过enqueue方法,发送请求。

  2. 请求到了Disptcher类中的队列中,然后加入到Disptcher的线程池中,执行execute方法,具体实现,是实现类中的AsycnCall当中的execute方法,然后经过拦截器链式调用,返回response,请求结束。

那么我们就开始研究一下这个链式调用是怎么展开的。

  //创建拦截器链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

我们可以先看创建拦截器链的时候两个比较重要的参数,第一个是我们的拦截器集合,第二个是0,对应的RealInterceptorChain这个类中的index参数,因为Interceptor.chain是接口,所以我们看实现类里的方法。

 @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

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

    calls++;

    // 重新创建RealInterceptorChain对象,将interceptors传入,同时脚标变成index+1
    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;
  }

到这再缕一缕:

  1. 首先创建了连接器链,将连接器集合传给了RealInterceptorChain,然后index传的是0,紧接着调用了RealInterceptorChain的proceed方法。在调用RealInterceptorChain的proceed方法的时候,会新建RealInterceptorChain对象,同时脚标+1,传入的还是之前的集合,这样就能一直的反复调用下去,同时和interceptors集合数量能对应上,直到最后一个集合调用完毕为止,返回response。

其实从代码当中也能看出来

    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;
}

 Interceptor是个接口,系统拦截器都会实现这个方法,最终都会由RealInterceptorChain的Response response = interceptor.intercept(next);这个方法返回response对象。

这样就是链式调用一步一步将request向下执行,然后一步一步向上返回response,最终返回Response对象,也就是 Response response = getResponseWithInterceptorChain();这个方法的详细流程。

小结:

请求的核心是链式调用,通过一个集合去维护,将request一步一步的经过每个连接器向下执行,到最后一个拦截器之后一步一步向上返回response。

这就是okhttp的请求流程。下一章我将会总结一下okhttp的拦截器的作用和连接池原理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值