美文网首页
okHttp 源码解析

okHttp 源码解析

作者: 4e70992f13e7 | 来源:发表于2021-04-26 15:24 被阅读0次

    OkHttp 源码详解

    OkHttp应该是目前Android平台上使用最为广泛的开源网络库了,Android 在6.0之后也将内部的HttpUrlConnection的默认实现替换成了OkHttp。

    这篇文章的目的,了解okhttp的框架原理,以及责任链模式的使用。

    1、发送请求

    首先看一下,怎么发出一个同步/异步请求。

            /**
         * 同步发起请求
         *
         * @throws IOException
         */
        private void execute() throws IOException {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url("your url").build();
            Response syncResponse = client.newCall(request).execute();
        }
    
        /**
         * 异步发起请求
         *
         * @throws IOException
         */
        private void enqueue() {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url("your url").build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                }
            });
        }
    

    这一段代码就是日常使用OkHttp最常见的用法,跟进源码后,可以得到一张更为详细的流程图,通过这张图来看下内部的逻辑是如何流动的。

    809143-20180816162138233-707076029.png

    其实很简单,只有几个核心类,我们一个个来看一下。

    1. OkHttpClient
    2. Request 和 Response
    3. RealCall

    OkHttpClient:这个是整个OkHttp的核心管理类,所有的内部逻辑和对象归OkHttpClient统一来管理,它通过Builder构造器生成,构造参数和类成员很多,这里先不做具体的分析。

    Request 和Response:Request是我们发送请求封装类,内部有url, header , method,body等常见的参数,Response是请求的结果,包含code, message, header,body ;这两个类的定义是完全符合Http协议所定义的请求内容和响应内容。

    RealCall:负责请求的调度(同步的话走当前线程发送请求,异步的话则使用OkHttp内部的线程池进行);同时负责构造内部逻辑责任链,并执行责任链相关的逻辑,直到获取结果。虽然OkHttpClient是整个OkHttp的核心管理类,但是真正发出请求并且组织逻辑的是RealCall类,它同时肩负了调度和责任链组织的两大重任,接下来我们来着重分析下RealCall类的逻辑。

    大致总结就是,OkHttpClient 和 Request 都是使用了 Builder 设计模式,然后,Request 通过 OkHttpClient 把 同步/异步 请求发送出去.

    2、同步/异步

    我们跟进源码,看一下同步/异步的请求原理

    public Response execute() throws IOException {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        try {
          client.dispatcher().executed(this);
          Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } finally {
          client.dispatcher().finished(this);
        }
      }
    
    public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    

    可以看到最终的请求处理是 dispatcher 来完成的,接下来看下 dispatcher

     //最大并发请求书
     private int maxRequests = 64;
     //每个主机的最大请求数
     private int maxRequestsPerHost = 5;
     private Runnable idleCallback;
    
     /** 执行的线程池. Created lazily. */
     private ExecutorService executorService;
    
    //将要运行的异步请求队列
     /** 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<>();
    
    
     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<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
       }
       return executorService;
     }
    

    Dispatcher 有两个构造方法,可以自己指定线程池, 如果没有指定, 则会默认创建默认线程池,可以看到核心数为0,缓存数可以是很大, 比较适合执行大量的耗时比较少的任务。

    接着看 enqueue是如何实现的

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

    当正在运行的异步请求队列中的数量小于64, 并且 正在运行的请求主机数小于5,把请求加载到runningAsyncCalls 中并在线程池中执行, 否则就加入到 readyAsyncCalls 进行缓存等待。

    上面可以看到传递进来的是 AsyncCall 然后 execute 那我们看下 AsyncCall方法

    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 {
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
      }
    

    看到 NamedRunnable 实现了 Runnable,AsyncCall 中的 execute 是对网络请求的具体处理。

    Response response = getResponseWithInterceptorChain();
    

    能明显看出这就是对请求的处理,在看它的具体实现之前先看下 client.dispatcher().finished 的方法实现。

      /** Used by {@code AsyncCall#run} to signal completion. */
      void finished(AsyncCall call) {
        finished(runningAsyncCalls, call, true);
      }
    
      /** Used by {@code Call#execute} to signal completion. */
      void finished(RealCall call) {
        finished(runningSyncCalls, call, false);
      }
    
    // 最后调用这个
      private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
        int runningCallsCount;
        Runnable idleCallback;
        synchronized (this) {
          if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
          if (promoteCalls) promoteCalls();
          runningCallsCount = runningCallsCount();
          idleCallback = this.idleCallback;
        }
    
        if (runningCallsCount == 0 && idleCallback != null) {
          idleCallback.run();
        }
      }
    

    由于 promoteCalls 是true 我们看下 promoteCalls 的方法实现

    private void promoteCalls() {
      if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
      if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall call = i.next();
    
        if (runningCallsForHost(call) < maxRequestsPerHost) {
          i.remove();
          runningAsyncCalls.add(call);
          executorService().execute(call);
        }
    
        if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
      }
    }
    

    根据代码可以明显看出 , 当一个请求结束了调用 finished 方法,最终到promoteCalls就是把 异步等待队列中的请求,取出放到 异步执行队列中。

    • 如果异步执行队列已经是满的状态就不加了,return
    • 如果 异步等待队列中 没有需要执行的网络请求 也就没有必要进行下一步了 return
    • 上面的两条都没遇到,遍历 异步等待队列,取出队首的请求,如果这个请求的 host 符合 (正在执行的网络请求中 同一个host最多只能是5个)的这个条件, 把 等待队列的这个请求移除, 加入到 正在执行的队列中, 线程开始执行。 如果不符合继续 遍历操作。

    3、interceptors 拦截器

    接着看 RealCall 的 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()));
        //处理 缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应
        //设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
        //可配置用户自己设置的缓存拦截器
        interceptors.add(new CacheInterceptor(client.internalCache()));
        //连接拦截器 这里才是真正的请求网络
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            //配置okhttpClient 时设置的networkInterceptors
           //返回观察单个网络请求和响应的不可变拦截器列表。
          interceptors.addAll(client.networkInterceptors());
        }
        //执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据
        //进行http请求报文的封装与请求报文的解析
        interceptors.add(new CallServerInterceptor(forWebSocket));
        //创建责任链
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
            //执行 责任链
        return chain.proceed(originalRequest);
      }
    

    看下 RealInterceptorChain 的实现

    public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
        Connection connection) throws IOException {
     
      if (index >= interceptors.size()) throw new AssertionError();
    
      calls++;
      //创建新的拦截链,链中的拦截器集合index+1
      RealInterceptorChain next = new RealInterceptorChain(
          interceptors, streamAllocation, httpCodec, connection, index + 1, request);
        //  执行当前的拦截器
      Interceptor interceptor = interceptors.get(index);
      // 执行拦截器
      Response response = interceptor.intercept(next);
    
         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;
    }
    

    根据上面的代码 我们可以看出,新建了一个RealInterceptorChain 责任链 并且 index+1,然后 执行interceptors.get(index); 返回Response。

    责任链中每个拦截器都会执行chain.proceed()方法之前的代码,等责任链最后一个拦截器执行完毕后会返回最终的响应数据,而chain.proceed() 方法会得到最终的响应数据,这时就会执行每个拦截器的chain.proceed()方法之后的代码,其实就是对响应数据的一些操作。

    结合源码,可以得到如下结论:

    拦截器按照添加顺序依次执行
    拦截器的执行从RealInterceptorChain.proceed()开始,进入到第一个拦截器的执行逻辑
    每个拦截器在执行之前,会将剩余尚未执行的拦截器组成新的RealInterceptorChain
    拦截器的逻辑被新的责任链调用next.proceed()切分为start、next.proceed、end这三个部分依次执行
    next.proceed() 所代表的其实就是剩余所有拦截器的执行逻辑
    所有拦截器最终形成一个层层内嵌的嵌套结构

    了解了上面拦截器的构造过程,我们再来一个个的分析每个拦截器的功能和作用。
    从代码来看,总共添加了五个拦截器(不包含自定义的拦截器如client.interceptors和client.networkInterceptors,这两个后面再解释)。
    我们本次分享,只做整体框架的解读,具体每个拦截器的处理不在此做出赘述。

    • retryAndFollowUpInterceptor——失败和重定向拦截器
    • BridgeInterceptor——封装request和response拦截器
    • CacheInterceptor——缓存相关的过滤器,负责读取缓存直接返回、更新缓存
    • ConnectInterceptor——连接服务,负责和服务器建立连接 这里才是真正的请求网络
    • CallServerInterceptor——执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据 进行http请求报文的封装与请求报文的解析

    4、拦截器demo

    个人觉得,okhttp的精髓之一,就是拦截器的理念,针对本理念,写了个简单易懂的demo,请笑纳。

    Interceptor拦截器接口

    public interface Interceptor {
        String intercept(OkHttpChain chain);
    }
    

    Interceptor拦截器链

    public class OkHttpChain {
        private int index = 0;
        private List<Interceptor> interceptors;
    
        public OkHttpChain(List<Interceptor> interceptors, int index) {
            this.interceptors = interceptors;
            this.index = index;
        }
    
        public String process() {
            if (index >= interceptors.size()) {
                return "";
            }
            OkHttpChain next = new OkHttpChain(interceptors, index + 1);
            Interceptor interceptor = interceptors.get(index);
            return interceptor.intercept(next);
        }
    
        public void add(Interceptor interceptor) {
            interceptors.add(interceptor);
        }
    }
    

    三个Interceptor拦截器

    public class AInterceptor implements Interceptor {
        @Override
        public String intercept(OkHttpChain chain) {
            System.out.println("Interceptor_A");
            return "A" + chain.process();
        }
    }
    
    public class BInterceptor implements Interceptor {
        @Override
        public String intercept(OkHttpChain chain) {
            System.out.println("Interceptor_B");
            return "_B" + chain.process();
        }
    }
    
    public class CInterceptor implements Interceptor {
        @Override
        public String intercept(OkHttpChain chain) {
            System.out.println("Interceptor_C");
            return "_C" + chain.process();
        }
    }
    

    执行

        public static void main(String[] args) {
            List<Interceptor> interceptors = new ArrayList<>();
            OkHttpChain chain = new OkHttpChain(interceptors, 0);
            interceptors.add(new AInterceptor());
            interceptors.add(new BInterceptor());
            interceptors.add(new CInterceptor());
            String result = chain.process();
            System.out.println("result = " + result);
        }
    

    执行结果为:

    Interceptor_A
    Interceptor_B
    Interceptor_C
    result = A_B_C
    

    参考博客

    相关文章

      网友评论

          本文标题:okHttp 源码解析

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