0.前言
okhttp是一个有square开发网络请求框架,square出品,必属精品。以前也看过这个框架的源码,但是时间久了,好多都记不清了,悔当初没有好好记录下来,今天有时间,又看了一遍,把思路分析记录下来。
1.基本使用
从最简单的Get请求分析,okhttp请求分为同步请求和异步请求:
同步请求:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
}
异步请求:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
代码分析就从这最基本的开始。
2.基本流程
先看同步请求,首先创建了一个Request,Request采用了建造者模式,可以很好的避免构造函数参数的数量爆棚,Request代表了一个http请求,包含了请求方法,请求头,和请求体。
接着是调用了OkHttpClient的newCall(request)
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
这个方法返回一个RealCall,接着看RealCall的newRealCall这个静态方法
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;
}
可以看到这里是真正RealCall的创建,里面包含了okhttpclient还有request,同时为这个RealCall注册了一个事件监听,这个eventListenerFactory就是在构建okhttp的时候传入的
new OkHttpClient.Builder()
.eventListenerFactory(PrintingEventListener.FACTORY)
.build();
网络请求的结果被封装在Response里,通过调用RealCall的execute方法,得到最终结果,所以可想而知,真正的网络请求也是在这一个过程进行的。接着就看一下execute方法
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
这个方法先判断是否已经执行该Call了,如果executed=true,那么就抛出异常,如果为false,就调用client.dispatcher().executed(this);Dispatcher根据注释来看,是用来决定何时执行异步策略的,看一下它的executed方法
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
runningSyncCalls是一个双向列表,这个方法就是单纯的将该RealCall添加进列表,所以网络请求不是在这里发起的,那么回到RealCall的execute方法,在dispatcher的executed方法调用后,接着调用了
getResponseWithInterceptorChain();该方法返回了Response,所以可以看出真正的网络请求是在这里做的。看一下这个方法:
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);
}
这个方法的前办部分构建了一个拦截器列表,包括我们在构建okhttpclient时添的interceptor和networkInterceptor,接着又生成了一个RealInterceptorChain,调用它的proceed方法返回最终的Response。
这个proceed方法,就是我们要关注的重点:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
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.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
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;
}
注重看这两行
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
可以看到每次调用proceed方法,都会生成一个新的RealInterceptorChain,其他参数都一样,只是index增加了1,接着就是根据index在拦截器列表找到一个拦截器,然后调用拦截器的intercept方法,并将刚才生成的RealInterceptorChain传入,所以现在大家应该清楚了吧,在自定义拦截器时复写的intercept方法传入Chain,其实是RealInterceptorChain,在复写拦截器的时候,经常会写chain.processed(request),之后就会重复之前的过程,如果你不调用chain.processed(request)方法,你会发现没有网络请求发出(没有http缓存的情况下),这是因为整个网络请求过程采用的是责任链模式,不调用这个方法,就相当于断掉了这个链条的传递,因为最终的请求的发出和Response的构建是在CallServerInterceptor里完成的,是链条的最后一环,这里注意的是resposne是由下向上返回的,类似于递归。得到response后,我们再回到Realcall的execute方法,看最后有一个finally
client.dispatcher().finished(this);
调用dispatcher的finished方法
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
将call从dispatcher的列表中移除。并重置RunningCount的数量,当runningCallsCount的数量为0时,会回调idleCallback。
接下来看一下异步的get请求, client.newCall(request).enqueue,同样是生成了一个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));
}
给方法还是调用了Dispatcher的enqueue方法,,但是你发现这里生成了一个新对象AsyncCall。
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
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 {
client.dispatcher().finished(this);
}
}
}
它有一个父类NamedRunnable,先看他的父类
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 {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
NamedRunnable是一个抽象类,并且实现了runnable接口,在run方法里调用了execute这个抽象方法。
我们在回到AsyncCall,看他的execute方法
try {
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 {
client.dispatcher().finished(this);
}
getResponseWithInterceptorChain(),熟悉吧,还是原来的配方,还是原来的味道。再看Dispatcher的enqueu方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
很显然,现将这个call添加到一个双向列表,然后启用了一个线程池,调用了这个AsyncCall。最后也是调用dispatcher的finish方法。
盗张图
image3.拦截器
从刚才分析的流程来看,拦截器是重点,okhttp允许我们自定义拦截器,也有一些默认的拦截器,下面分析一下这些拦截器的作用:
RetroyAndFollowUpInterceptor:处理重定向和失败重连
BridgeInterceptor:请求前添加一些http header,保存cookie,处理zip
CacheInterceptor:处理http响应缓存
ConnectInterceptor:建立与服务器的链接
CallServerInterceptor:发送request并解析response
这里只是简单说一下其作用,有时间单拿出一篇文章详细分析。
image关注我的公众号
网友评论