主要参考文章:
1.Okhttp的基本使用
2.Okhttp主流程源码分析
Okhttp 3.12.0 使用例子
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("ziq", "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("ziq", "onResponse: " + response.body().string());
}
});
1、初始化
建造者模式,public OkHttpClient() { this(new Builder());} 初始化了一些配置信息:支持协议、任务分发器(其内部包含一个线程池,执行异步请求)、连接池(其内部包含一个线程池,维护connection)、连接/读/写超时时长等信息。
public Builder() {
dispatcher = new Dispatcher();//任务调度器
protocols = DEFAULT_PROTOCOLS;//支持的协议 Protocol.HTTP_2, Protocol.HTTP_1_1
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;//根据地址与证书 进行校验X509Certificate
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;//身份验证
authenticator = Authenticator.NONE;//身份验证
connectionPool = new ConnectionPool();//连接池
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
下面列出 Dispatcher 的主要分析部分
//Dispatcher.java
public final class Dispatcher {
private int maxRequests = 64;//最大请求数量
private int maxRequestsPerHost = 5;//每台主机最大的请求数量
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;//线程池
private final Deque readyAsyncCalls = new ArrayDeque<>();//等待队列
private final Deque runningAsyncCalls = new ArrayDeque<>();//异步运行中队列
private final Deque runningSyncCalls = new ArrayDeque<>();//同步运行中队列
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
。。。
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);//添加到异步运行队列中
}
promoteAndExecute();//将 readyAsyncCalls中的call 添加到 runningAsyncCalls并运行
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//正在运行的任务数是否大于 64
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//对应主机 的 正在运行的任务数是否大于 5
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
。。。
}
2、生成call 并 请求
//OkHttpClient.java
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
//RealCall.java
new RealCall(client, originalRequest, forWebSocket);
@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的代码中可知道,call直接加入到 readyAsyncCalls队列中,然后 在promoteAndExecute方法中判断是否 可以执行 readyAsyncCalls中的任务,如果可以则 把任务加入到runningAsyncCalls ,并 到线程池中执行。
3、执行call
asyncCall.executeOn(executorService());
AsyncCall extends NamedRunnable implements Runnable
,所以运行run() ->execute() ;
final class AsyncCall extends NamedRunnable {
。。。
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
try {
//1、进过一系列拦截器后,返回结果
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 {
//2、结束当前call,运行未执行且符合条件的call
client.dispatcher().finished(this);
}
}
}
4、Interceptor拦截器
到了这里,到达了okhttp最核心的部分, Interceptor,采用了责任链的设计模式
4.1client.dispatcher().finished(this);
//Dispatcher.java
private void finished(Deque calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
可以看到,移除call后,又回到 一开始 的promoteAndExecute() 方法,去把readyAsyncCalls中的call 拿出来运行。
4.2 责任链
Response response = getResponseWithInterceptorChain();进过一系列拦截器后,返回结果
//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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);
}
添加的各Interceptor,分别负责功能:
client.interceptors() 用户自定义的Interceptor,能拦截到所有的请求
RetryAndFollowUpInterceptor 负责失败重连和重定向相关
BridgeInterceptor 负责配置请求的头信息,比如Keep-Alive、gzip、Cookie等可以优化请求
CacheInterceptor 负责缓存管理,使用DiskLruCache做本地缓存,CacheStrategy决定缓存策略
ConnectInterceptor 开始与目标服务器建立连接,获得RealConnection
client.networkInterceptors() 用户自定义的Interceptor,仅在生产网络请求时生效
CallServerInterceptor 实际网络请求的地方。
递归实现:
1、RealInterceptorChain.proceed(...) 为开头,会生成 下一步的RealInterceptorChain next1,与当前的RealInterceptorChain参数一样,区别是index 加1
了,所以会调用 下一级 拦截器的interceptor1.intercept(next)
2、interceptor1.intercept(next)调用 下一个链 next1.proceed(...)方法
3、next1.proceed(...)调用下一个interceptor2.intercept(next) 形成 递归
4、最后的拦截器是 CallServerInterceptor,返回response,然后一级一级返回response。
//RealInterceptorChain.java
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,RealConnection connection)throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
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 (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
//1、生成 下一步的RealInterceptorChain,与当前的RealInterceptorChain参数一样,区别是index 加1 了
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//2、Interceptor interceptor内会调用 next.proceed(...) 又回到这里的第一步,再生成一个chain 形成递归
Response response = interceptor.intercept(next);
//结束递归
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
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;
}
各个拦截器部分细节描述:
拦截器 | 描述 |
---|---|
RetryAndFollowUpInterceptor | 生成 StreamAllocation 实例,后面的拦截器使用 |
BridgeInterceptor | 添加header参数 |
CacheInterceptor | 默认是没有缓存的,全都是直接网络请求。 |
ConnectInterceptor | 利用上面 的StreamAllocation 建立 HttpCodec、RealConnection实例从connectionPool 寻找是否有RealConnection,有就直接赋值给StreamAllocation 中的connection 找不到就result = new RealConnection(connectionPool, selectedRoute);新建,赋值给StreamAllocation并且缓存到connectionPool |
CallServerInterceptor | 使用前面其他拦截器生成的 StreamAllocation , RealConnection, HttpCodec;而HttpCodec 中使用okio 通过 Socket 传输数据,网络请求。 |