一、OkHttp的基本使用
//构建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new RequestIntercept())
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.build();
//构建Request对象
Request request = new Request.Builder()
.get()
.url("http://www.test.com")
.build();
//根据request对象创建RealCall对象
Call call = okHttpClient.newCall(request);
//通过RealCall发起异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
上述代码是okhttp的基本使用,下面简述下其流程:
- 第一步先构建OkHttpClient对象,通过builder模式构建配置参数,包括自定义拦截器、连接和读写超时时间等一些配置
- 构建Request请求对象,也是通过builder模式构建请求参数,包括请求方式(get/post)、请求url、请求体参数(post请求需要)
- 根据Request请求对象创建能够发起请求的对应的RealCall对象,RealCall的构造方法中传入了OkHttpClient对象和Request对象,这样RealCall就持有了这两个对象的所有信息
- 通过RealCall的enqueue方法发起异步请求,并设置请求监听回调
二、OkHttp的执行流程
通过OkHttp的基本使用可以知道,先构建出OkHttpClient对象和Request对象,通过这两个对象配置请求需要的参数数据,然后根据这两个对象构建出RealCall,然后通过RealCall的enqueue方法发起异步请求,下面看下enqueue方法的源码:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
//注释1
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
在注释1处,调用了调度器dispatcher的enqueue方法,并向调度器中添加了一个AsyncCall任务对象(AsyncCall是一个Runnable),跟着查看下dispatcher的enqueue方法:
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
在这个方法中可以看到有两个队列readyAsyncCalls和runningAsyncCalls,runningAsyncCalls是正在执行请求的队列,readyAsyncCalls是准备进行请求的队列,当正在执行的请求队列的长度大于最大请求数maxRequests时,就会将该请求任务添加到缓存队列readyAsyncCalls中,当请求数和域名都满足最大值要求时,就会将请求任务添加到runningAsyncCalls中,并通过线程池执行该任务,由于AsyncCall是一个Ruannable对象,所以放到线程池中执行时,会调用其run方法,AsyncCall的直接父类是NamedRunnable,这个类中重写了run方法,最终AsyncCall的执行代码是在其execute方法中进行的,所以查看下AsyncCall的execute方法:
@Override protected void execute() {
boolean signalledCallback = false;
try {
//注释2
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
//注释3
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
//注释4
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);
//注释5
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//注释6
client.dispatcher().finished(this);
}
}
在注释2处进行了拦截器链的调用最终返回一个Response响应,注释3和5回调响应失败,注释4回调响应成功,在注释6处的finished方法中,会从runningAsyncCalls执行队列中移除该任务,然后将readyAsyncCalls的任务取出来添加到runningAsyncCalls中,这个过程在调用链的promoteCalls方法中,下面看下dispatcher的finished方法和promoteCalls方法:
void finished(AsyncCall call) {
//runningAsyncCalls正在执的任务队列
finished(runningAsyncCalls, call, true);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//calls.remove(call))从runningAsyncCalls中移除该任务
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//调用promoteCalls()方法,调整任务队列
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
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();
//将readyAsyncCalls中的任务取出添加到正在执行的队列中
runningAsyncCalls.add(call);
//通过线程池执行从readyAsyncCalls中刚取出的任务
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
在注释2处的getResponseWithInterceptorChain()方法执行的是拦截器链的调用:
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, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
拦截器是典型的责任链模式,从上述方法中可以看出,所有的拦截器都按照顺序存放到一个list中,按照添加顺序进行递归调用,先添加的是用户自定义的拦截器,其次是重试和重定向处理拦截器retryAndFollowUpInterceptor、补全请求信息的拦截器BridgeInterceptor(添加一些基础的请求头信息)、缓存处理拦截器CacheInterceptor、con连接拦截器ConnectInterceptor,然后是网络拦截器,最后是向服务端进行I/O读写处理的拦截器CallServerInterceptor,每个拦截器只负责自己对应的职责,这些拦截器层层处理,最终返回一个用户需要的Response响应数据,其实okhttp的请求过程,可以看成是各个拦截器处理的过程
上面的拦截器中可以分为两类,一类是应用拦截器,另一类是网络拦截器networkInterceptor,网络拦截器和应用拦截器有什么区别呢,主要是调用时机的问题,用户自定义的应用拦截器调用的最早,在应用拦截器中只能拿到原始的请求信息并且获取不到connection对象,不能操作中间响应,只能操作最终的响应信息,而网络拦截器是在请求补全、缓存、connection处理之后进行调用的,所以网络拦截器能够拿到完整的网络请求,能够对重定向和重试等中间响应进行操作,可以获取到connection对象
本文详细介绍了OkHttp的基本使用方法及内部执行流程,包括构建OkHttpClient和Request对象,通过RealCall发起异步请求,以及AsyncCall任务的调度与执行。深入解析了OkHttp的拦截器机制,区分应用拦截器与网络拦截器的功能与调用时机。
596

被折叠的 条评论
为什么被折叠?



