okhttp流程分析(一)

okhttp在Android开发中已经很广泛了,所以理解其内部机制是很有必要的。

首先看一下最基本的okhttp的请求流程

GET请求:

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();
}
  1. 创建OkHttpClient的对象。我们可直接new出来 也可以通过OkHttpClient.Builder()构建。
  2. 创建Request对象。
  3. 通过OkHttpClient创建一个请求的任务Call。
  4. 同步请求直接执行任务 call.execute(),返回结果Response
  5. 异步请求执行call.enqueue(new Callback()…) 在callback回调中接收返回的结果Response

POST请求:

public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}
  1. 创建OkHttpClient的对象。我们可直接new出来 也可以通过OkHttpClient.Builder()构建。
  2. 通过指定返回类型和post的参数创建RequestBody
  3. 创建Request对象。
  4. 通过OkHttpClient创建一个请求的任务Call。
  5. 同步请求直接执行任务 call.execute(),返回结果Response
  6. 异步请求执行call.enqueue(new Callback()…) 在callback回调中接收返回的结果Response

通过上面的基础用法,我们可以看到这几个对象:OkHttpClient,Request,Call,Response ,call.execute(),call.enqueue(new Callback()…) ,下面一一分析。

OkHttpClient

这个类代码看着有差不多一千行,其实大部分代码只要是初始化了后面需要用到的各种对象,如分发器dispatcher,各种拦截器,连接池connectionPool,缓存cache等等。
内部使用了构建者模式通过Builder创建各种对象。
最主要的一个方法就是newCall(Request request)返回一个Call对象。

Request
封装一个请求

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

通过构建者模式初始化,内部封装了请求需要的url,请求类型,参数,请求头,请求体。
请求体RequestBody是一个抽象类它有两个实现类 FormBody和MultipartBody,这两个分别对应了我们post请求的时候的表单提交和文件提交。

Call
上面的例子中,创建完Request请求之后,通过OkHttpClient的newCall创建了一个Call对象。Call是什么呢?
Call是一个接口,是okhttp的核心类之一,我们通过它去执行网络请求。内部有个工厂接口将对象的创建延迟到子类中去创建。它的实现类就是RealCall。
我们也可以从OkHttpClient中的创建中看到,最后返回了RealCall对象。

@Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false );
  }
  1. RealCall创建的时候,传了3个参数,一个是OkHttpClient,一个是Request,第三个用的少标记是不是webSokcet。所以RealCall可以方便的使用OkHttpClient和Request
  2. RealCall中有两个重要的方法execute() 和enqueue(Callback responseCallback) 分别对应了同步请求和异步请求。
  3. RealCall中还有一个很重要的方法getResponseWithInterceptorChain()。给请求添加拦截器。这个是okhttp的设计上的一个很灵活的地方,可以给请求添加自己想要的各种拦截器。系统自带的拦截器有重试重定向拦截器RetryAndFollowUpInterceptor,设置编码方式,添加头部信息,链接复用等拦截器BridgeInterceptor,缓存拦截器CacheInterceptor,网络链接拦截器ConnectInterceptor,发起网络请求接收网络响应拦截器CallServerInterceptor。这些拦截器都很重要,以后再一一分析。

下面主要先看一下execute() 和enqueue(Callback responseCallback) 同步和异步方法:

最开始的例子中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);
      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);
    }
  }

首先第一个判断

 synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

判断这个call是否被执行过,执行过就抛异常了。说明一个call只能执行一次。
然后执行captureCallStackTrace()方法 从方法名字可以看出 是捕获call的堆栈跟踪信息

private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

在之后进入到核心类 Dispatcher中的client.dispatcher().executed(this)方法了。

Dispatcher这个对象在OkHttpClient初始化的时候就创建了。

下面看一下Dispatcher中的executed方法

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

首先synchronized 加锁了,是线程安全的。把call放入runningSyncCalls中

private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

可以看到runningSyncCalls是一个双向队列。所以executed()方法就是把一个call放入到队列中。

然后就走到Response result = getResponseWithInterceptorChain()方法了

可以看到这个方法就返回了一个响应Response 。

而这个getResponseWithInterceptorChain()方法做了什么呢?

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //添加开发者应用层自定义的Interceptor
    interceptors.addAll(client.interceptors());
     //这个Interceptor是处理请求失败的重试,重定向    
    interceptors.add(retryAndFollowUpInterceptor);
     //这个Interceptor工作是添加一些请求的头部或其他信息
    //并对返回的Response做一些友好的处理
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
     //这个Interceptor的职责是判断缓存是否存在,读取缓存,更新缓存等等
    interceptors.add(new CacheInterceptor(client.internalCache()));
     //这个Interceptor的职责是建立客户端和服务器的连接
    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);
  }

可以看到里面创建了一个ArrayList,不断往里面添加各种拦截器。最后通过这些拦截器创建一个Interceptor.Chain对象(拦截器的链)最后调用了chain.proceed()方法。
看一下proceed()方法的内部:

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

    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);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

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

可以看到经过一系列的判断之后,又创建了一个名字叫next的RealInterceptorChain 对象。这个对象跟chain唯一的不同就是index加一了。其实这其中的意思就是遍历执行各个拦截器的proceed方法。直到执行到最后一个拦CallServerInterceptor,CallServerInterceptor中就不往下执行了,开始封装响应参数。

封装完后再依次往前传递,最后给第一个拦截器。最后执行到executed()方法中的 Response result = getResponseWithInterceptorChain(),最后返回响应的Response 给前端。

executed()方法的finally中,无论执行成功与否都回收掉所有的资源。

finally {
      client.dispatcher().finished(this);
    }

Response
封装一个返回响应

Response(Builder builder) {
    this.request = builder.request;
    this.protocol = builder.protocol;
    this.code = builder.code;
    this.message = builder.message;
    this.handshake = builder.handshake;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.networkResponse = builder.networkResponse;
    this.cacheResponse = builder.cacheResponse;
    this.priorResponse = builder.priorResponse;
    this.sentRequestAtMillis = builder.sentRequestAtMillis;
    this.receivedResponseAtMillis = builder.receivedResponseAtMillis;
  }

也是通过构建者模式创建,内部封装了响应头,响应体,响应码,协议等。
响应体ResponseBody也是一个抽象类,它有两个实现CacheResponseBody,RealResponseBody分别代表了缓存的响应和真实的响应。

上面主要分析了同步的请求,下面看一下异步的请求,同步了解了,异步就好点了。异步的代码如下:这里要注意一点enqueue中的onFailure和onResponse方法都是在子线程中执行的,如果想操作界面还是得回到主线程

 OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().url("").build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

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

            }
        });

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

最终还是执行到了Dispatcher中的enqueue方法传入了一个AsyncCall。看一下Dispatcher中的enqueue方法:

  synchronized void enqueue(AsyncCall call) {
     //如果正在执行的请求小于设定值即64,并且请求同一个主机的request小于设定值即5
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //添加到执行队列,开始执行请求
      runningAsyncCalls.add(call);
      //获得当前线程池,没有则创建一个
      executorService().execute(call);
    } else {
    //添加到等待队列中
      readyAsyncCalls.add(call);
    }
  }

这里我们看到runningAsyncCalls和readyAsyncCalls 这个是跟上面的同步请求中的runningSyncCalls一块定义的都是双向队列

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

异步请求有两个队列,一个是等待队列readyAsyncCalls 。一个是正在执行的队列runningAsyncCalls 。正在执行的队列有上线 由参数maxRequests和maxRequestsPerHost 控制,正在执行的请求小于64个,并且请求同一个主机小于5的时候才往这个队列中添加这个call,并放到线程池中去执行,否则就放到等待的队列中去。

从上面我们看到传入enqueue的参数是一个AsyncCall ,AsyncCall 继承了NamedRunnable,NamedRunnable实现了 Runnable。所以AsyncCall 本质上就是一个Runnable。

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

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

所以这个AsyncCall 在线程池中最终也会执行到它的run方法。run方法里面最终执行到了execute()方法。这个execute()中执行的就跟我们同步请求的execute()基本一样了。

OK到这里okhttp的同步和异步的请求流程就通了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值