OkHttp是android源码中提供的网络请求框架,是Square公司的经典作品之一
源码 git@github.com:square/okhttp.git
以下源码分析基于3.9.0
1. OkHttp3使用步骤
使用步骤可分为4步:
1.1 创建OkHttpClient
Builder模式创建OkHttpClient,可以添加自定义拦截器,以及配置各种参数(鉴权、超时等)。
1.2 创建Request
Builder模式创建请求对象,配置请求url以及method,自定义请求头Header也是在这里添加。
1.3 创建Call
OkHttpClient#newCall(request)
具体实现为RealCall,将OkHttpClient以及Request包装成RealCall对象。
1.4 将call提交到队列
请求分为两种:异步Async、同步Sync。
1. 异步请求
调用call.enqueue(callback), 内部实现是将call加入runningAsyncCalls并调用线程池执行或者readyAsyncCalls等待执行;
2. 同步请求
调用call.execute(callback),内部实现是将call加入runningSyncCalls,在当前线程执行请求.
这些容器都是双端队列ArrayDeque,具体执行细节后面再详细描述。
示例代码如下:
// step 1
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
OkHttpClient client = clientBuilder.build();
// step 2
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.url("https://www.baidu.com");
// step 3
Call call = client.newCall(requestBuilder.build());
// step 4
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("IOException: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.toString());
System.out.println("body: " + response.body().string());
}
});
2. 源码时序图分析 (异步请求为例)
时序图描述了用户发起一个 异步请求RealCall ,到RealCall返回callback响应结果的大概逻辑。
RealCall如何拿到response?这里还涉及到Dispatcher以及RealInterceptorChain的逻辑,后续章节再详细描述。
2.1 创建OkHttpClient与添加拦截器
Interceptor可以帮助我们分析、处理请求过程(修改Request与Response)。
private OkHttpClient getOkHttpClient() {
File file = new File(CACHE_PATH);
if (!file.exists()) {
file.mkdirs();
}
Cache cache = new Cache(file, CACHE_SIZE);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.addInterceptor(InterceptorManager.getRequestInterceptor()) // Request拦截器
.addInterceptor(InterceptorManager.getResponseInterceptor()) //Response拦截器
.addInterceptor(InterceptorManager.getLogInterceptor()) // Log拦截器
.addNetworkInterceptor(InterceptorManager.getNewWorkInterceptor())
.cache(cache)//开启缓存
.build();
return client;
}
2.2 添加请求(以异步请求为例)
2.2.1 RealCall#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));
}
RealCall内部逻辑实现,将请求交给Dispatcher来管理与分发。
2.2.2 Dispatcher#enqueue
按照当前请求队列的情况,添加到对应的队列中,对请求数量进行有效的管控。
runningAsyncCalls
进行请求 的队列,当进行请求队列数量<64 && 目标Host同时处理的请求<5,则将call添加到队列,并且调用线程池执行当前请求。
readyAsyncCalls
等待请求 的队列,不满足上述条件,call就加入等待请求队列。
2.2.3 Dispatcher#promoteCalls
当一个请求完成后,检测是否需要将readyAsyncCalls中的请求转移到runningAsyncCalls队列。
RealCall#AsyncCall内部执行完请求,会在finally代码块触发promoteCalls方法。
1.runningAsyncCalls队列容量已达到64,返回
2.没有达到64,则迭代readyAsyncCalls队列,将call转到进行队列并调用线程池执行请求
3.转移一个call,就需要再检查进行队列容量,达到64就退出
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
// 如果runningAsyncCalls队列“已满”,则加入等待队列readyAsyncCalls
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
// 完成一个请求,则进行判断,是否需要将等待队列中的请求移动到进行队列中,有则进行移动操作,并开始请求
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.
}
}
2.3 线程池的实现
// 自定义线程池,核心线程为0
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;
}
2.4 Call - RealCall - AsyncCall
传入的Call对象实为AsyncCall,AsyncCall是RealCall的内部类,实现类Runnable接口。
AsyncCall 持有RealCall的originalRequest以及responseCallback。
execute()方法中,完成请求,并invoke通知callback回调,最后还要通知上面步骤2.2.3的操作,检测是否可以将等待队列中的call转移到进行队列中。
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 {
// run()方法中调用execute()
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
// 此抽象方法,是每一个Call对象的具体实现,模板方法模式
protected abstract void execute();
}
AsyncCall#execute(),调用流程在父类中定义,这里是具体实现,模版方法模式。
@Override protected void execute() {
boolean signalledCallback = false;
try {
// 获取请求结果Response
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 {
// 完成请求,触发call从等待队列到进行队列的转移
client.dispatcher().finished(this);
}
}
3 类图说明
- OkHttpClient用来创建请求,添加Interceptor;
- RealCall是Call的实现类,用来发起请求,AsyncCall定义了异步请求过程;
- Dispatcher用来管理请求队列,触发线程池进行请求(异步请求调用线程池,同步请求只是用dispatcher来管理请求队列);
- Interceptor的实现类是具体的请求过程,责任链模式;
- 请求结果response在AsyncCall中返回给Client。
说明:上述步骤均是指异步请求,关于同步请求有几点不同
第2步,同步请求直接在RealCall#execute()方法中执行;
第3步,同步请求只是用dispatcher来管理请求队列(进行队列:runningAsyncCalls + runningSyncCalls);
第5步,同步请求结果直接在RealCall#execute()方法中返回。