美文网首页
okhttp分析

okhttp分析

作者: 哇楼主 | 来源:发表于2019-11-01 16:29 被阅读0次

    okhttp使用分为同步请求和异步请求:
    异步请求:

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

    request是一个请求对像,包含了请求url,methord,heard等信息
    okhttpclient 主要用于发送http请求以及读取回应
    newcall方法主要是用于返回一个realcall对象,并且把请求对象request交给了realcall

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

    接下来看一下realcall的enqueue方法:

    @Override public void enqueue(Callback responseCallback) {
     synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    

    首先通过同步,确保call不会被重复执行(如果想要完全相同的call可以通过clone方法),然后利用dispatcher调度器来执行enqueue方法,下面看一下dispatcher.enqueue方法:

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

    dispatcher就是一个异步请求是的策略,它里面包含了能同时进行的最大请求数(默认是64),同时请求相同host的最大数(默认是5),以及维护一个异步任务执行队列和一个异步任务等待队列,然后回来看dispatcher.enqueue方法,首先会判断当前执行队列是不是超出最大请求数,以及同时访问相同host的数量是不是超过,如果超过就将call放入等待队列,否则放入执行队列,并且交给线程池去执行
    执行的为AsyncCall,我们看一下AsyncCall的实现:

    final class AsyncCall extends NamedRunnable { 
    

    AsyncCall继承自NamedRunnable,NamedRunnable其实是继承自Runnable,在他的run方法中会调用execute();方法,说到底其实就是会执行AsyncCall的execute();方法,接下来看一下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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
    

    可以看到真正执行请求的是getResponseWithInterceptorChain(),获取到response后回调给用户,值得注意的是最后finally,会通过调度器移除队列,并且判断如果执行队列没有达到最大值则把等待队列变为执行队列,这样就包证了等待队列的执行
    下面我们看一下真正请求的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);
    return chain.proceed(originalRequest);
    }
    

    我们可以看到方法中首先创建一个拦截器的列表,添加各个拦截器,每个拦截器个自完成自己的任务,并且将不属于自己的任务交给下一个,这就是一种责任链模式,最后的执行是由chain.proceed(originalRequest);来实现的,责任链中每个拦截器都会执行chain.proceed()方法之前的代码,等责任链最后一个拦截器执行完毕后会返回最终的响应数据,而chain.proceed() 方法会得到最终的响应数据,这时就会执行每个拦截器的chain.proceed()方法之后的代码,其实就是对响应数据的一些操作。

    @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++;
    
    // 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);
    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");
    }
    
    return response;
    }
    

    简述okhttp的执行流程:

    • OkhttpClient 实现了Call.Fctory,负责为Request 创建 Call;
    • RealCall 为Call的具体实现,其enqueue() 异步请求接口通过Dispatcher()调度器利用ExcutorService实现,而最终进行网络请求时和同步的execute()接口一致,都是通过 getResponseWithInterceptorChain() 函数实现
    • getResponseWithInterceptorChain() 中利用 Interceptor 链条,责任链模式 分层实现缓存、透明压缩、网络 IO 等功能;最终将响应数据返回给用户。

    相关文章

      网友评论

          本文标题:okhttp分析

          本文链接:https://www.haomeiwen.com/subject/avzfbctx.html