主要流程篇 OkHttp源码相关(一) 。
拦截器篇 OkHttp源码相关(二) 。
1.主要流程
image.png在使用OkHttp发起一次请求时,对于使用者最少存在OkHttpClient
、Request
与Call
三个角色。其中OkHttpClient
和Request
的创建可以使用它为我们提供的Builder
(建造者模式)。而Call
则是把Request
交给OkHttpClient
之后返回的一个已准备好执行的请求。
Call
的execute
代表了同步请求,而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;
}
网友评论