OkHttp基本原理浅析

作者: 像程序那样思考 | 来源:发表于2019-07-22 15:23 被阅读8次

    我们先来看下OkHttp的两个使用方法
    同步:

       //同步执行方法,不应该在UI线程使用
        response = client.newCall(request).execute();
        //异步方法    
        response = client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                    }
                }
            });
    
    让我们进入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;
        }
    

    可以看到返回了一个RealCall对象,接下来继续看RealCall是个什么东西,主要看他的 execute和enqueue方法

      @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()来具体执行的,看到了似曾相识的interceptor,其实这里是运用了责任链设计模式的拦截器,这个稍后再说 execute方法暂时先告一段落,接下来看enqueue

       @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        //看来这里才是真正执行的方法,继续跟踪,发现了一个dispather,并且还new了一个AsyncCall对象,传入了我们的匿名内部类接口实例
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
        }
    

    上面跟踪到了一个dispather,这个又是个什么鬼?字面理解是分发器,看来事情没有这么简单啊,继续跟进

      synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          //咦,这个不是线程池嘛 
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
        }
    

    我们逮到了dispather的enqueue,发现他的call是丢给了线程池了,那么这个call,也就是AsyncCall是什么?先来看看它吧

       /**
          *注意这个类在RealCall类里面哦,是其内部类
          */
         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;
        }
    
        //发现AsyncCall也有一个execute方法,和RealCall差不多
        @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;
              //这个是传进来的回调啦,它不是UI线程
              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);
              //这个也是传进来的回调啦,它也不是UI线程
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
        }
    

    原来它实现了NamedRunnable,那么这个NamedRunnable应该是实现了Runnable,然后我们这个execute没有在这里被调用,猜想应该是被父类重写的run给调用了,然后这个run应该是在线程池中的,验证下

     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的enqueued来,是不是思路清晰多了。
    首先,newCall(request)初始化request后生成了一个RealCall,紧接着RealCall的execute开始执行这个请求,如果异步,就是传入enqueue(callback),然后调用dispather.enqueue(new AsyncCall(callback)),这个AsyncCall呢他是RealCall内部类所以同样可以访问到newCall(request)初始化后的request,它持有callback回调同时又是个Runnable,并且它的run方法调用了他自己和外部类RecalCall名称相同功能相似的execute方法,然后这个AsyncCall在dispather里面是丢给线程池执行的,这样一来问题就通了。

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

    说了这么久dispather?这个dispather到底是啥?别急,继续看

     private int maxRequests = 64;
         private int maxRequestsPerHost = 5;
         ...
         public Dispatcher(ExecutorService executorService) {
        this.executorService = executorService;
        }
    
        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;
        }
    

    原来真是个线程池的封装类。。。这个线程池核心线程0,非核心线程int的最大值,但是外面maxRequest和 maxRequestsPerHost已经限制了它的并发线程数了,非核心线程60s超时时间,阻塞队列是SynchronousQueue,也就是不存储元素的队列,进了必出。到此问题已经基本解决。

    下面说一下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, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());
    
        return chain.proceed(originalRequest);
        }
    

    继续看chain.proceed,看之前顺便提下责任链设计模式。典型的责任链模式,是定义一个责任链节点对象抽象类,定义一个消息抽象类,每个节点对象必须实现抽象类的handleMessage(Object message)方法,然后对传进来的消息按实际情况处理,未处理完或者不能处理的交给下一个链节点对象,直到消息处理完毕。

    责任链体现了典型的分层思想,分层的好处是显而易见的,复杂简单化,灵活和易于维护。比如TCP/IP协议就是经典的例子。

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

    简单总结下上面代码,其实大概就是getResponseWithInterceptorChain()里面先实例化一条责任链,注册各种拦截器(链节点对象),然后通过chain.proceed获得下一个拦截器(节点)

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

    每次调用chain对象proceed获得节点后,节点的intercept取出chain里面的request处理,然后用户在里面又调用procee,index+1,获得下一个拦截器,然后调用拦截器的拦截方法intercept,用户里面又取出chain里面的request处理,继续循环下去。

    简要说下拦截器

    • 应用拦截器(用户添加)
    • 重定向等的拦截器
    • 构造请求头的拦截器
    • 缓存拦截器
    • 连接拦截器
    • 网络拦截器(用户添加)
    • 数据传输拦截器
      最后附上网络上的两个图总结
      OkHttp流程

    拦截器


    最后

    如果你看到了这里,觉得文章写得不错就给个呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

    希望读到这的您能转发分享关注一下我,以后还会更新技术干货,谢谢您的支持!

    转发+点赞+关注,第一时间获取最新知识点

    Android架构师之路很漫长,一起共勉吧!
    ——————分割线——————
    简书点赞可以有好几种赞,长按点赞按钮就会有选项,大家点赞的时候,麻烦点个超赞~

    相关文章

      网友评论

        本文标题:OkHttp基本原理浅析

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