Android开发中会用到各种各样的框架,熟悉框架的原理是进阶中必不可少的部分,然而只是跟着源码走一遍,很容易就遗忘了,所以想到了用博客来记录分析的过程,当然写博客时候也必定会查阅大量资料,这对框架的分析是有好处的。
okhttp是目前主流的网络请求框架,retrofit的内嵌的网络请求也是使用okhttp进行的。本文主要研究okhttp的源码流程与相关知识。也会记录自己阅读源码的一些姿势。
源码的入口应该从常用的地方着手。下图为okhttp实际使用的情景。
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("url")
.addHeader("user_agent","tongZhang")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response)
throws IOException {
}
});
首先创建OkHttpClient的实例,点进去看看。发现采用了Builder模式进行OkHttpClient相关属性的初始化。
public static final class Builder {
Dispatcher dispatcher;
@Nullable Proxy proxy;
List protocols;
List connectionSpecs;
final List interceptors = new ArrayList<>();
final List networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable Cache cache;
@Nullable InternalCache internalCache;
SocketFactory socketFactory;
@Nullable SSLSocketFactory sslSocketFactory;
@Nullable CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
ConnectionPool connectionPool;
Dns dns;
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
这里只需要大概了解每个属性的作用就可以了,有的变量从命名就可以了解它的含义,有的变量类需要点进去看到它的具体作用,一些注释也会帮助我们了解。
Dispatcher不明白,点进去。
/**
* Policy on when async requests are executed.
*
* Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your
* own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number
* of calls concurrently.
*/
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque runningSyncCalls = new ArrayDeque<>();
上面的英文注释看不懂可以借助翻译,大概意思是 当异步请求执行时。再大概瞄几眼这个类的属性和方法。发现了它是跟请求相关的,还出现了一些ThreadPoolExecutro的东西,不管了,知道它大体是负责异步请求执行相关的东西就好了。
Proxy,点进去发现是一些请求类型,不过在new Builder中没找到proxy的赋值,不管了。
/**
* This class represents a proxy setting, typically a type (http, socks) and
* a socket address.
* A {@code Proxy} is an immutable object.
*
* @see java.net.ProxySelector
* @author Yingxian Wang
* @author Jean-Christophe Collet
* @since 1.5
*/
public class Proxy {
/**
* Represents the proxy type.
*
* @since 1.5
*/
public enum Type {
/**
* Represents a direct connection, or the absence of a proxy.
*/
DIRECT,
/**
* Represents proxy for high level protocols such as HTTP or FTP.
*/
HTTP,
/**
* Represents a SOCKS (V4 or V5) proxy.
*/
SOCKS
};
大概就这么分析下来会知道
protocols是一些http版本的头信息集合。
connectionSpecs是HTTP套接字连接的配置集合。
interceptors是Interceptor的集合,从英文注释上了解到是拦截器,大概就是修改请求头和反馈一些响应。
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
networkInterceptors跟interceptors类似,从字面意思理解是跟网络相关的拦截器集合。
eventListenerFactory从字面上像是个监听器。点进去看看。
eventListenerFactory = EventListener.factory(EventListener.NONE);
public abstract class EventListener {
public static final EventListener NONE = new EventListener() {
};
static EventListener.Factory factory(final EventListener listener) {
return new EventListener.Factory() {
public EventListener create(Call call) {
return listener;
}
};
}
结合代码与英文注释分析确实是获得了个初始化后的Factory接口,一旦执行create就会获得这个监听器,call大概是请求,由请求来得到一个监听,感觉也蛮合适的。
ProxySelector是proxy(上面已经分析过了)的选择器。
CooKieJar不会是服务器那边cookie session那个东西吧?
public interface CookieJar {
/** A cookie jar that never accepts any cookies. */
CookieJar NO_COOKIES = new CookieJar() {
@Override public void saveFromResponse(HttpUrl url, List cookies) {
}
@Override public List loadForRequest(HttpUrl url) {
return Collections.emptyList();
}
};
没准还真是,这里默认是选择不接受任何cookie。
socketFactory是socket工厂,负责生产socket,源码也简单,我就不贴了,太占篇幅了。
hostnameVerifier貌似是一些认证,http的握手认证。(分析英文注释)
cettificatePinner是一些证书的管理。还是握手协议那块的东西。(分析英文注释)
proxyAuthenticator和authenticator是对请求头的一些反馈。(分析英文注释)
* <p>When authentication is requested by an origin server, the response code is 401 and the
* implementation should respond with a new request that sets the "Authorization" header.
* <pre> {@code
*
* if (response.request().header("Authorization") != null) {
* return null; // Give up, we've already failed to authenticate.
* }
*
* String credential = Credentials.basic(...)
* return response.request().newBuilder()
* .header("Authorization", credential)
* .build();
* }</pre>
*
* <p>When authentication is requested by a proxy server, the response code is 407 and the
* implementation should respond with a new request that sets the "Proxy-Authorization" header.
* <pre> {@code
*
* if (response.request().header("Proxy-Authorization") != null) {
* return null; // Give up, we've already failed to authenticate.
* }
*
* String credential = Credentials.basic(...)
* return response.request().newBuilder()
* .header("Proxy-Authorization", credential)
* .build();
connectionPool是连接池,当前容纳五个空闲的连接,存活时间是五分钟。
* Create a new connection pool with tuning parameters appropriate for a single-user application.
* The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
* this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
*/
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
this.maxIdleConnections = maxIdleConnections;
this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
// Put a floor on the keep alive duration, otherwise cleanup will spin loop.
if (keepAliveDuration <= 0) {
throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
}
}
dns大家应该不陌生,是映射ip与域名的服务器。属于网络相关的一个属性。
剩下一些基本类型,顾名思义,思不到意也没关系。
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
OkHttpClient的所有属性先摸上一遍,不用深入分析,知道各自的用处就好了,后续的分析还会再次用到这些属性,前面的分析只是方便后面源码的分析。
接着最初的入口分析。OkHttpClient的实例创建完了,接着又创建了request请求的实例。
Request request = new Request.Builder()
.url("url")
.addHeader("user_agent","tongZhang")
.build();
这个就不需要分析了,简单的Builder模式,封装成一个请求类的实例。
接着看。
Call call = client.newCall(request);
点进去。
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的实例,点进去看构造方法,发现只是赋值了相关属性,并初始化了一个名为RetryAndFollowUpInterceptor的拦截器。
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
/**
* There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward.
* This will be set after we create the call instance then create the event listener instance.
*/
private EventListener eventListener;
/** The application's original request unadulterated by redirects or auth headers. */
final Request originalRequest;
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
返回上图会发现之前分析的eventListener出现了。
call.eventListener = client.eventListenerFactory().create(call);
根据之前的分析确实是由这个创建的RealCall的实例create生成了eventListener监听器。
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
这个call实际上就是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));
}
首先判断executed是否执行过,若是执行过就抛异常,确保执行一次。captureCallStackTrace方法看名字是捕捉调用栈的信息。
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
Platform.get得到Android平台,再点进getStackTraceForCloseable方法,根据英文注释了解此方法会返回一些堆栈跟踪的信息。将此信息赋值给retryAndFollowUpInterceptor,至于为什么这么做,先往后看。
eventListener.callStart(this);
监听器执行callStart方法,关于监听器更详细的内容可以点进去详细分析下,这里不做深入。继续看。
client.dispatcher().enqueue(new AsyncCall(responseCallback));
responseCallback是开放给我们定义的回调接口,这里通过new AsyncCall进行封装。
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
进入dispatcher的enqueue方法。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
根据注释和代码分析得知,runningAsyncCalls是正在运行的异步请求队列。runningCallsForHost(call)是跟此call相同的host的数量,意思就是当前正在运行的异步请求队列小于64,并且相同host请求数量小于5就先执行add.后执行execute。如果请求过多,则加入readyAsync队列待命。
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;
}
继续分析executorService方法。发现这里会通过线程池来执行异步请求。执行AsyncCall。
@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);
}
}
}
重点是这个getResponseWithInterceptorChain()返回Response了,后面的判断是为了执行相关回调接口与监听器的回调方法。
getResponseWithInterceptorChain是通过拦截器链得到response,这个下一篇会讲到。