OkHttp3的分析过程将以以下代码调用过程进行:
//步骤1:创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build();
//步骤2:创建Request对象
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get()
.build();
//步骤3:创建Call对象
Call call = client.newCall(request);
//步骤4:进行请求
//异步请求方式
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("Fail");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
//同步请求方式
Response response = call.execute();
OkHttpClient创建过程是一个构建者模式应用的过程,OkHttpClient类有个静态内部类Builder
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
final Dispatcher dispatcher;//请求分发器,负责将请求任务保存至队列,并分发到某个空闲线程,接着执行,执行完关闭任务。
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//默认支持的协议,如Protocol.HTTP_2, Protocol.HTTP_1_1
final List<ConnectionSpec> connectionSpecs;//连接Connection的参数配置,如加密认证的TLS连接,普通未加密未认证的连接等
final List<Interceptor> interceptors;//请求过程中的拦截器,包括连接建立之前和之后的所有拦截器
final List<Interceptor> networkInterceptors;//网络拦截器
final EventListener.Factory eventListenerFactory;//请求状态监听
final ProxySelector proxySelector;//代理选择器
final CookieJar cookieJar;//默认是没有Cookie的
final @Nullable Cache cache;//缓存
final @Nullable InternalCache internalCache;//内部缓存
final SocketFactory socketFactory;//创建Socket的工厂
final @Nullable SSLSocketFactory sslSocketFactory;//创建加密认证Socket的工厂
final @Nullable CertificateChainCleaner certificateChainCleaner;//安全相关配置
final HostnameVerifier hostnameVerifier;//安全相关配置
final CertificatePinner certificatePinner;//安全相关配置
final Authenticator proxyAuthenticator;//安全相关配置
final Authenticator authenticator;//安全相关配置
final ConnectionPool connectionPool;//连接池
final Dns dns;//域名解析系统 domain name -> ip address
final boolean followSslRedirects;//在加密认证的情况下,是否支持重定向
final boolean followRedirects;//是否支持重定向
final boolean retryOnConnectionFailure;//连接失败时,是否重试
final int connectTimeout;//连接超时时间
final int readTimeout;//读取响应超时时间
final int writeTimeout;//写入请求超时时间
final int pingInterval;//WebSocket相关,为了保持长连接,使用Ping命令维持连接。
//构造者模式
public static final class Builder {
Dispatcher dispatcher;
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> 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;
//初始化
public Builder() {
dispatcher = new Dispatcher();//直接new了一个对象
protocols = DEFAULT_PROTOCOLS;//默认的协议
connectionSpecs = DEFAULT_CONNECTION_SPECS;//默认的连接规格
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;//默认无cookies
socketFactory = SocketFactory.getDefault();//默认的SocketFactory
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();//直接new一个连接池对象,
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;//默认可以重定向
retryOnConnectionFailure = true;//默认连接失败后,自动重试
connectTimeout = 10_000;//连接超时
readTimeout = 10_000;//读超时
writeTimeout = 10_000;//写超时
pingInterval = 0;
}
}
一些重要的成员变量的解析:
Dispatcher:负责维护请求队列,分发请求至连接池,执行请求,结束请求,并进行任务执行的调度,执行下一个请求;
ConnectionSpec:Socket连接的规格属性,内部通过构建者模式进行对象的创建,看源码中的两个例子:
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
/** A modern TLS connection with extensions like SNI and ALPN available. */
//有加密和认证的连接
public static final ConnectionSpec MODERN_TLS = new Builder(true)
.cipherSuites(APPROVED_CIPHER_SUITES)
.tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
.supportsTlsExtensions(true)
.build();
/** Unencrypted, unauthenticated connections for {@code http:} URLs. */
//无加密和认证的连接
public static final ConnectionSpec CLEARTEXT = new Builder(false).build();
Interceptor:拦截器,OkHttp在后续处理请求的时候,应用了牛逼的拦截器链模式。其中有失败重试/重定向拦截器,桥接拦截器,缓存拦截器,连接建立拦截器,网络请求拦截器。用户也可以自定义拦截器,用户自定义的拦截器会放在拦截器链的开始位置,最先执行。
ConnectionPool:Socket连接池,在建立连接时可以在连接池中查找是否有可用的连接。在初始化的时候,new ConnectionPool()的时候:
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
//maxIdleConnections:最多可空闲的连接数量
//keepAliveDuration:保活时间;TimeUnit前面保活时间的时间单位
//源码中默认是:连接池中最多可有5个空闲的连接,并且,这5个连接如果在5分钟内一直空闲,将被移除连接池,即关闭。
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);
}
}
最后OkHttpClient中的内部类中Builder的build方法完成OkHttpClient的创建工作:
public OkHttpClient build() {
return new OkHttpClient(this);
}
//调用这个构造方法
//全是引用传递,因为具体的初始化过程,已经在Builder中完成了
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;
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);
}
}
整体来看,OkhttpClient的创建过程是一个非常典型的构造者模式的应用,同时也是一个外观模式的应用,我们应用者仅仅通过非常简短的代码调用,即可完成非常复杂的初始化过程;
构造者模式应用时机:在非常复杂的对象创建的过程中;这样可以防止必须提供多个构造器。如上面的OkhttpClient类中有多个成员属性变量,但是在创建对象的时候我们根据不同的需求,可能需要使用其中不同组合的成员属性,这个时候如果不实用构造者模式,就需要提供多个构造器。而使用构造者模式,我们就可以非常灵活的初始化OkhttpClient,无论它使用什么样的成员变量组合。
再看一下Request的创建过程,同样,它也是一个非常典型的构造者模式的应用。
public final class Request {
final HttpUrl url;//请求的URL
final String method;//请求方法,post get
final Headers headers;//请求头部
final @Nullable RequestBody body;//请求内容
final Object tag;//在取消这个请求是时候会用到
private volatile CacheControl cacheControl; // Lazily initialized.
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;
Object tag;
public Builder() {
this.method = "GET";//请求方法默认是GET方法
this.headers = new Headers.Builder();
}
public Builder url(HttpUrl url) {
if (url == null) throw new NullPointerException("url == null");
this.url = url;
return this;
}
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
HttpUrl parsed = HttpUrl.parse(url);
if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
return url(parsed);
}
}
public Builder addHeader(String name, String value) {
headers.add(name, value);
return this;
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);//转到Request构造其中,同样的味道,同样的料
}
}
通过上述两个过程,创建了OkHttpClient和Request两个对象。
OkHttpClient比喻成一辆车,Request就好比我们要去的目的地,现在已经确定了目的地,接下来就是路途上会发生哪些事情了。