OkHttp是个目前比较流行的网络请求框架,现在大部分的应用都有在用它,看了很多大佬们写的OKHttp相关的博客,在这里记录下自己的分析过程。由于OkHttp内容比较多,这篇文章主要先简单分析下OkHttp请求的基本流程。
首先,在分析源码之前先看下使用OkHttp请求的示例代码:
val okHttpClient = OkHttpClient.Builder()
.readTimeout(15, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("https://blog.csdn.net/qq_21612413/article/details/87358000")
.build()
val call = okHttpClient.newCall(request)
// 同步请求
// val response = call.execute()
// 异步请求
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
println("failure")
}
override fun onResponse(call: Call, response: Response) {
println("response:${response.body()?.string()}")
}
})
可以看到,基本流程是先构建OkHttpClient和Request实例,然后通过调用newCall方法,传入request对象获得一个Call对象,通过这个Call对象来发起同步或异步请求。
通过有两个方式来获取OkHttpClient实例,一种是默认的构造方法,另一种是使用Builder模式
来构建对象。
val okHttpClient = OkHttpClient()
其内部构造函数使用了Builder对象,使用的都是默认配置:
public OkHttpClient() {
this(new Builder());
}
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
... 省略
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
val okHttpClient = OkHttpClient.Builder()
.readTimeout(15, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
可使用OkHttpClient.Builder
类配置参数,最后调用build
方法返回一个OkHttpClient对象。
public OkHttpClient build() {
return new OkHttpClient(this);
}
val request = Request.Builder()
.url("https://blog.csdn.net/qq_21612413/article/details/87358000")
.build()
构建了一个OkHttpClient对象之后,我们还需要构建一个Request对象,通过查看它的构造函数可以看到,它也需要通过Builder模式
来构建。
public static class Builder {
@Nullable
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tags = request.tags.isEmpty()
? Collections.emptyMap()
: new LinkedHashMap<>(request.tags);
this.headers = request.headers.newBuilder();
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
}
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
val call = okHttpClient.newCall(request)
val response = call.execute()
通过newCall方法获取到Call对象后,再执行同步或异步请求,先看下newCall方法的内部实现:
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
RealCall类:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
可以看到,Call对象实际是RealCall类型
。
执行Call的enqueue方法:
public void enqueue(Callback responseCallback) {
// 判断是否已执行,如果已执行,则抛出异常
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 捕获并设置堆栈信息日志
captureCallStackTrace();
eventListener.callStart(this);
// 执行Dispatcher的enqueue方法
// AsyncCall对象,该对象继承NamedRunnable
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
可以看到,enqueue方法不能被重复执行,否则会抛出IllegalStateException异常,该方法最后会执行Dispatcher的enqueue方法,传入了一个AsyncCall对象
:
void enqueue(AsyncCall call) {
synchronized (this) {
// 将请求放入异步准备队列
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
// 遍历异步准备队列
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
// 取出Call对象
AsyncCall asyncCall = i.next();
// 判断异步Running队列的数量是否小于最大请求数量(默认为64)
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
// 判断请求同一主机的个数是否小于maxRequestsPerHost(最大可请求主机个数,默认是5)
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost)
continue; // Host max capacity.
// 将Call对象移出异步准备队列
i.remove();
// 添加到执行集合
executableCalls.add(asyncCall);
// 添加到异步Running队列
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
// 遍历待执行集合
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
// 调用Call对象的executeOn方法
// executorService返回一个线程池对象
asyncCall.executeOn(executorService());
}
return isRunning;
}
该方法的作用主要是把任务放入readyAsyncCalls(异步准备队列),然后再遍历该队列判断任务是否可以被执行,如果可以,则将任务放入一个待执行对象集合中,最后遍历待执行对象集合将任务逐个放入线程池中执行,接下来看下AsyncCall的executeOn方法(传入的参数是个线程池对象):
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
// 放入线程池中执行,AsyncCall继承了NamedRunnable对象,NamedRunnable的run方法执行了execute方法
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
可以看到,由于AsyncCall继承自NamedRunnable类(实现了Runnable 接口),所以executorService.execute(this)会去执行NamedRunnable的run
方法:
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() {
// 在执行之前把当前线程的名字改为由构造生成的name,执行完execute方法后再把线程名字改回去
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute(); // 执行
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
最后执行了execute方法:
protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
e = timeoutExit(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 {
client.dispatcher().finished(this);
}
}
在execute方法中,会通过getResponseWithInterceptorChain方法
(拦截器处理)返回Response对象
,如果请求被取消了,则返回onFailure失败回调,否则,返回onResponse成功回调。这里需要注意的是,请求被取消,会回调到onFailure方法。接下来我们再来看下同步请求的流程:
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 堆栈信息跟踪
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try {
// 调用Dispatcher的executed方法,将Call对象添加进同步运行队列中
client.dispatcher().executed(this);
// 经过各种拦截器处理后最终返回Response对象
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
// Dispatcher的executed方法
synchronized void executed(RealCall call) {
this.runningSyncCalls.add(call);
}
同步请求相对简单,在该方法中把Call对象放入了runningSyncCalls(同步运行队列)中,最终也调用getResponseWithInterceptorChain方法返回Response对象
。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 构建个拦截器的集合
List<Interceptor> interceptors = new ArrayList<>();
// 添加自定义的拦截器
interceptors.addAll(client.interceptors());
// 添加错误处理和重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
// 封装request和response过滤器
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));
// 构建RealInterceptorChain,传入拦截器集合,request对象等,注意index为0这个参数
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
// 调用proceed方法
return chain.proceed(originalRequest);
}
构建了个拦截器的集合,将它传入RealInterceptorChain对象,通过该对象来完成拦截器的链式调用。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
// 如果index大于或等于拦截器集合个数,则抛出异常
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
// 构建一个next的RealInterceptorChain,index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 取出拦截器
Interceptor interceptor = interceptors.get(index);
// 调用拦截器的intercept方法,传入next对象,拿个拦截器看下里面具体的实现是怎样的
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
注意index这个参数,默认传入是为0,当构建一个next的RealInterceptorChain时,此时index+1了。执行流程是当前拦截器链会根据index取出对应位置的拦截器,调用拦截器的intercept方法,传入next对象。接着在拦截器中又会调用next对象的proceed方法,重新进入这个方法,然后又调用下一个拦截器的intercept方法(此时index+1),形成链式调用,直到最后一个拦截器(CallServerInterceptor)不调用next对象的proceed方法为止,最后逐级返回response对象。
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//1 Request阶段,该拦截器在Request阶段负责做的事情
//2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
//3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
return response;
}
}
这篇文章主要分析了下OKHttp的基本流程,还有很多细节还没有分析,例如拦截器等,在对整体有了清晰认识之后,再单独进行深入分析理解起来会相对简单点。最后用一张图(图来源于拆轮子系列:拆 OkHttp,感谢作者)来回顾下基本的请求流程: