美文网首页
OkHttp源码相关(一)-主要流程

OkHttp源码相关(一)-主要流程

作者: 来lol里 | 来源:发表于2021-01-14 19:44 被阅读0次

    主要流程篇 OkHttp源码相关(一)
    拦截器篇 OkHttp源码相关(二)

    1.主要流程

    image.png

    在使用OkHttp发起一次请求时,对于使用者最少存在OkHttpClientRequestCall三个角色。其中OkHttpClientRequest的创建可以使用它为我们提供的Builder(建造者模式)。而Call则是把Request交给OkHttpClient之后返回的一个已准备好执行的请求。
    Callexecute代表了同步请求,而enqueue则代表异步请求。两者唯一区别在于一个会直接发起网络请求,而另一个使用OkHttp内置的线程池来进行。Dispatcher分发器就是来调配请求任务的,内部会包含一个线程池。可以在创建OkHttpClient时,传递我们自己定义的线程池来创建分发器,最后调用Interceptors拦截器,也是ok的核心部分,网络请求最终会在这里发送出去,最终返回相应的Response

    具体使用方法

     //         创建OkHttpClient对象
                    OkHttpClient client = new OkHttpClient();
                    //创建Request
                    Request request = new Request.Builder()
                            .url(url)//访问连接
                            .get()
                            .build();
                    //创建Call对象        
                    Call call = client.newCall(request);
                    //通过execute()方法获得请求响应的Response对象        
                    Response response = call.execute();
              
    

    (4.0.x以后 底层变成kotlin)

    2.具体分析

    1. 准备工作OkHttpClient和Request

    这两个主要是网络请求之前的一些准备工作,如网络地址,get或者post请求等,可以看到是用到了Builder建造者模式。

    2. Dispatcher分发器和异步请求

    下一步就是这个方法 Call call= okHttpClient.newCall(request);,我们看一下newCall这个方法,主要调用的是RealCall的newRealCall方法,然后用到了工厂模式,然后给我一个call。

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

    下一步我们看一下里边的execute()方法,这个方法主要调用的是Dispatcher 分发器里的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));
        }
    
    image.png

    分发器中的enquequ异步请求方法的时候,首先要判断一下当前正在跑的请求任务是不是超出了最大限制maxRequests(默认64可),再判断同一个host服务器的请求是不是超过maxRequestsPerHost(默认5个),如果两个都符合,则添加到正在执行的队列,并提交线程池,如果不符合,则加入等待队列。

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

    这里看下AsyncCall这个方法,继承NamedRunnable这个抽象方法,实际上就是个Runnable接口,方便我们在线程池使用,最终调用的还是execute()这个方法。

    public abstract class NamedRunnable implements Runnable {
        protected final String name;
    
    ···
    
        @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();
    }
    

    而AsyncCall中的getResponseWithInterceptorChain()方法是核心方法,他会调用后边的拦截器实现具体的发起网络请求的方法,然后返回给我们一个请求结果Response,一次完整的网络请求就完成了。

    final class AsyncCall extends NamedRunnable {
           
        @Override
        protected void execute() {
          boolean signalledCallback = false;
          try {
            Response response = getResponseWithInterceptorChain(); //核心方法
           ...
          } catch (IOException e) {
           ...
          } finally {
            //请求完成之后要移除 里边是个remove的操作
            client.dispatcher().finished(this);
          }
        }}
           
            }
        }
    

    线程池的方法其实就和Executors.newCachedThreadPool()创建的线程一样。首先核心线程为0,表示线程池不会一直为我们缓存线程,线程池中所有线程都是在60s内没有工作就会被回收。而最大线程Integer.MAX_VALUE与等待队列SynchronousQueue的组合能够得到最大的吞吐量。即当需要线程池执行任务时,如果不存在空闲线程不需要等待,马上新建线程执行任务!等待队列的不同指定了线程池的不同排队机制。

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

    相关文章

      网友评论

          本文标题:OkHttp源码相关(一)-主要流程

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