一、同步&异步请求主线流程
1.1、异步请求
String hostname = "baidu.com";
//自签名校验
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/asdasdasdasdasdadasdsdBBBBBBB=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
1.2、关键类
OkhttpClient
、Request
、Call
、RealCall
、AsyncCall
、Dispatcher
OkhttpClient
:是Okhttp请求的管理类,通过构建者模式创建Request
:是请求参数的封装类,也是通过构建者模式创建Call
&RealCall
:Call是一个接口,定义了同步&异步请求的方法enqueu()&excute(),RealCall是Call的实现类负责具体的请求实现Dispatcher
:负责请求调度,内部定义了两个双端队列readyAsyncCalls和runningAsyncCalls,异步请求添加到runningAsyncCall中,不同的host数量大于等于5或者同时请超过64个,则先添加到等待队列readyAsyncCalls中AsyncCall
:readyAsyncCalls和runningAsyncCalls队列的元素,是Runnable子类,在子线程中负责执行请求,并回调结果
1.3、代码分析
下面看代码,执行一个异步的http请求
//先执行newCall获得RealCall,再调用RealCall的enqueue方法
client.newCall(request).enqueue(Callback responseCallback)
//step 1: newCall()返回了RealCall对象
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
final class RealCall implements Call {
//step 2: 调用Real了Call的enqueu方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//step 3: 调用Dispatcher的enqueue方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
来看一下Dispatcher的定义
public final class Dispatcher {
//正在并行执行的请求总数最大值
private int maxRequests = 64;
//不通host的请求最大值
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
//执行请求的线程池
private @Nullable ExecutorService executorService;
//双端队列实现的异步请求的等待请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//双端队列实现的异步请求正在执行的队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步请求的队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
//初始化线程池,0核心线程,Integer.MAX_VALUE熟练的非核心线程
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//异步方法执行请求
synchronized void enqueue(AsyncCall call) {
//如果正在执行的请求小于64 并且 正在运行的请求不同的host数量小于5,则通过线程池直接执行
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
//如果并行请求数量大于等于64或者不同host数量大于等于5,则先存放在等待队列中
readyAsyncCalls.add(call);
}
}
...
}
AsyncCall继承NamedRunnable实现了Runnable接口,上面通过线程池执行了AsyncCall时调动run方法
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
//step 1: 线程池执行Runnable,执行run()方法
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//step 2: 触发执行execute()方法,execute()在子类AsyncCall实现
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
final class RealCall implements Call {
//AsyncCall是RealCall中定义的,非静态内部类,
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
//step 3:执行execute()
@Override protected void execute() {
boolean signalledCallback = false;
try {
//step 4: 通过责任链模式组装的Chain获取到http请求的结果response
Response response = getResponseWithInterceptorChain();
//step 5: 请求结果通过responseCallback回调,onResponse或者onFailure
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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//step 6: 请求完成,移除队列里面对的请求,并执行下一个请求,这块的代码实现就不贴了
client.dispatcher().finished(this);
}
}
}
//具体的执行请求并返回请求结果,这个后续再分析
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);
return chain.proceed(originalRequest);
}
}
1.4、异步请求总结
总结一下Okhttp异步请求的主线流程
-
通过构建者模式创建OkhttpClient和Request,调用okhttpClient.newCall(request)获得RealCall
-
再调用RealCall的enqueue(Callback responseCallback)方法
-
RealCall的enqueue(Callback responseCallback)方法继续调用了Dispatcher().enqueue(Callback callback)方法
-
Dispatcher().enqueue(Callback callback)中判断如果正在运行的请求的host总数小于并且总请求数小于64,则直接通过线程池执行请求,否则就先加入等待队列中
-
每个请求通过AsyncCall这个Runnable子类包装,线程池执行请求时,会执行到AsyncCall的excute方法
-
在AsyncCall的excute方法中通过执行Okhttp的请求责任链,并获得请求结果Response
-
获取到Response后,通过responseCallback回调对应的请求结果
-
此时请求已完成,那么再从队列中移除这个请求,并触发线程池执行下一个请求
1.5、同步请求
至此一次异步请求完成,下面来看一下同步请求
同步请求更简单,添加到同步队列并通过责任链获取请求结果,实现如下
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
//step 1:添加到同步队列
client.dispatcher().executed(this);
//step 2:通过请求的责任链执行请求并返回结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
二、责任链模式
上面分析的主线流程没有对getResponseWithInterceptorChain()做分析,下面来看看里面的具体实现,他是如何一步一步获取到请求结果的
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
//step 1:添加我们自定义的应用拦截器
interceptors.addAll(client.interceptors());
//step 2:添加重试和重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
//step 3: 负责对请求行和请求头的组装,例如Content-Length的计算和添加、gzip的⽀持等
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//step 4: 网络缓存,如果请求满足缓存条件则直接从缓存里面取结果,不需要走后续的拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//step 5:负责创建TCP连接,如果是https请求的话,还要简历TLS连接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//step 6:添加我们自定义的网络拦截器,基本用不到
interceptors.addAll(client.networkInterceptors());
}
//step 7:负责请求与响应的IO操作,往Socket写请求数据和读取响应数据
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
Okhttp的拦截器是基于ArrayList实现的责任链模式
,拦截器分为应用拦截器
和网络拦截器
应用拦截器
:在所有其他Interceptor 处理之前,进⾏最早的预处理⼯作,以及在收到Response 之后,做最后的善后⼯作
。比如请求之前添加header,已经请求之后判断Response的响应码是否为token过期的401,如果token过期则刷新token并且重新请求等操作。网络拦截器
:开发中用的不多,在ConnectInterceptor之后也就是建立了TCP连接之后执行,可以做一些网络监控的功能,比如Facebook的stetho
库,Android应用通过引入stetho,可以在Chrome/Chromium浏览器监控查看网络请求
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000L, TimeUnit.MILLISECONDS)
.readTimeout(600000L, TimeUnit.MILLISECONDS)
//token过期自动刷新拦截器
.addInterceptor(new RefreshTokenInterceptor())
//Log打印
.addInterceptor(loggingInterceptor)
//facebook的stetho
.addNetworkInterceptor(new StethoInterceptor())
.build();
下面再看其他5个Okhttp提供的拦截器
RetryAndFollowUpInterceptor
:它负责在请求失败时的重试,以及重定向的⾃动后续请求。它的存在,可以让重试和重定向对于开发者是⽆感知的BridgeInterceptor
:它负责⼀些不影响开发者开发,但影响 HTTP交互的⼀些额外预处理。例如,Content-Length 的计算和添加、gzip 的⽀持(Accept-Encoding: gzip)、gzip压缩数据的解包,都是发⽣在这⾥CacheInterceptor
:它负责 Cache 的处理。把它放在后⾯的⽹络交互相关Interceptor 的前⾯的好处是,如果本地有了可⽤的 Cache,⼀个请求可以在没有发⽣实质⽹络交互的情况下就返回缓存结果,⽽完全不需要开发者做出任何的额外⼯作,让Cache 更加⽆感知ConnectInterceptor
:它负责建⽴连接。在这⾥,OkHttp 会创建出⽹络请求所需要的TCP 连接(如果是 HTTP),或者是建⽴在 TCP 连接之上的 TLS 连接(如果是 HTTPS),并且会创建出对应的 HttpCodec 对象(⽤于编码解码 HTTP 请求)CallServerInterceptor
:它负责实质的请求与响应的I/O操作,即往 Socket ⾥写⼊请求数据,和从 Socket ⾥读取响应数据