使用Okhttp3 进行一次同步请求,大概需要进行下面几部操作:
注:同步请求是阻塞式,直到HTTP响应返回。
try {
//1,构建 client
OkHttpClient client = new OkHttpClient.Builder().readTimeout(10,TimeUnit.SECONDS).build();//可以通过添加各种属性
//2,构建request请求
Request request = new Request.Builder().url("www.baidu.com").build();//可以继续添加各种数据
//3,获得call对象
Call call = client.newCall(request);
//4,执行同步请求
Response response = call.execute();
//...
} catch (IOException e) {
e.printStackTrace();
}
按照上面同步请求
的步骤跟踪源码进行一下简单的分析:
1,OkhttpClient
这里使用到了Builder
设计模式,来构建一个OkhttpClient
对象,可以设置缓存、超时、cookie管理等属性(如下)。
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher; //分发器
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;//cookie
this.cache = builder.cache;//缓存
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;//连接池
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;//超时
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
2,Request
通过Builder
构建一个请求,其中包含
-
url
请求的地址 -
method
get 、post -
headers
请求头 -
RequestBody
请求体
3,Call
public interface Call extends Cloneable {.....}
源码可以看出,Call是一个接口,需要找实现它的类RealCall
,具体的实现,都在RealCall
中
final class RealCall implements Call {.....}
从上面同步请求的步骤3可以看出Call的创建过程:Call call = client.newCall(request);
client 调用OkHttpClient.newCall
方法,其实就是调用了RealCall.newRealCall
得到一个 Call 如下,
//OkHttpClient.java
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
//RealCall.java
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;
}
4,call.execute()
执行同步方法
在执行同步方法的时候,call.execute()
实际上也是执行的RealCall .execut()
@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); //在这里,调用了分发器:Dispatcher.executed() 方法
Response result = getResponseWithInterceptorChain();//这个方法,生成拦截器链,后续分析
if (result == null) throw new IOException("Canceled");
return result;//将结果response返回
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);//最后的时候,会调用分发器:Dispatcher.finished() 方法
}
}
- 分析一下上面的client.dispatcher().executed(this);这里拿到的是
OkhttpClient.dispatcher
,并且执行了Dispatcher.executed()
方法
//Dispatcher.java
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);//添加到正在执行的同步队列中
}
//
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
- client.dispatcher().finished(this); 看一下这个方法,会调用到下面的
//同步的finished,会调到这里
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
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(); //此时,promoteCalls = false 不会进入promoteCalls();
runningCallsCount = runningCallsCount();//重新计算一下,正在运行的数量
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
网友评论