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

2021-01-14  本文已影响0人  来lol里

主要流程篇 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;
    }
上一篇下一篇

猜你喜欢

热点阅读