The internal implementation process of OkHttp3 was not considered when it was used before. Today, I will sort out and record it.
Next, I will add the common methods, internal classes and fields in the OkHttpClient class with my own understanding of comments, and understand the main purpose of OkHttpClient by looking at the comments.
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
//Default protocols Http1.1 and OkHttp2 supported by OkHttp
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1);
//Default connection rules
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
static {
/*The main purpose of this class object is to operate on the connection pool class, which ensures uniqueness.*/
Internal.instance = new Internal() {
//Set the internal cache of OkHttpClient
@Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) {
builder.setInternalCache(internalCache);
}
//The connection pool determines whether the specified connection is idle. If it is, clear the specified connection. Otherwise, scan the connection pool for expired idle connections.
@Override public boolean connectionBecameIdle(
ConnectionPool pool, RealConnection connection) {
return pool.connectionBecameIdle(connection);
}
//Get the same connection in the connection pool as the URL of this connection
@Override public RealConnection get(ConnectionPool pool, Address address,
StreamAllocation streamAllocation, Route route) {
return pool.get(address, streamAllocation, route);
}
//Compare the non host parts of two addresses (DNS, protocol, connection rules, etc.)
@Override public boolean equalsNonHost(Address a, Address b) {
return a.equalsNonHost(b);
}
//Mainly for the multiplexing of http2, the multiplexing connection pool is http2 connection and should meet the address requirements.
@Override public Socket deduplicate(
ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
return pool.deduplicate(address, streamAllocation);
}
//Put the connection into the connection pool and scan the connection pool for expired idle connections
@Override public void put(ConnectionPool pool, RealConnection connection) {
pool.put(connection);
}
//Get the corresponding code
@Override public int code(Response.Builder responseBuilder) {
return responseBuilder.code;
}
//Construct HttpUrl by checking whether the URL has syntax errors, throwing an exception if any, and dismembering the URL to HttpUrl if not.
@Override public HttpUrl getHttpUrlChecked(String url)
throws MalformedURLException, UnknownHostException {
return HttpUrl.getChecked(url);
}
//Gets the stream on the connection.
@Override public StreamAllocation streamAllocation(Call call) {
return ((RealCall) call).streamAllocation();
}
};
}
//Build yourself with the default Builder
public OkHttpClient() {
this(new Builder());
}
//Use the Custom Builder to build itself, which is to pass the parameters of builder to itself
OkHttpClient(Builder builder) {
/*
* . . . . . . . . . . . . .
* */
}
/** Default connect timeout (in milliseconds). */
public int connectTimeoutMillis() {
return connectTimeout;
}
/** Default read timeout (in milliseconds). */
public int readTimeoutMillis() {
return readTimeout;
}
/** Default write timeout (in milliseconds). */
public int writeTimeoutMillis() {
return writeTimeout;
}
//Get cache class object, operate cache
public Cache cache() {
return cache;
}
//To obtain the Cache class object inside the Cache class is actually to operate on the Cache class object
InternalCache internalCache() {
return cache != null ? cache.internalCache : internalCache;
}
//Get DNS (domain name reversal)
public Dns dns() {
return dns;
}
//Get connection pool
public ConnectionPool connectionPool() {
return connectionPool;
}
//Whether to redirect next
public boolean followRedirects() {
return followRedirects;
}
//Is reconnection disabled
public boolean retryOnConnectionFailure() {
return retryOnConnectionFailure;
}
//Get the distributor. The distributor class will be analyzed later
public Dispatcher dispatcher() {
return dispatcher;
}
//Get network connection protocol
public List<Protocol> protocols() {
return protocols;
}
//Get connection rules
public List<ConnectionSpec> connectionSpecs() {
return connectionSpecs;
}
//Get the normal interceptor, which is the first one to execute
public List<Interceptor> interceptors() {
return interceptors;
}
//Get all the network interceptors, which will be executed after connecting to the server
public List<Interceptor> networkInterceptors() {
return networkInterceptors;
}
//Obtain monitoring of network start and end connection process
EventListener.Factory eventListenerFactory() {
return eventListenerFactory;
}
//Instantiate the event that holds the request and the client (OkHttpClient)
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
//Build Builder with its own parameters
public Builder newBuilder() {
return new Builder(this);
}
/**
* Next is the Builder Design Pattern
* OkHttp More design patterns used
* If you don't know about the Builder mode, first understand it. Here is a summary of the Builder pattern: some fields of a class cannot be assigned by itself and need to be delegated to other classes.
*/
public static final class Builder {
//Using the default parameters of Builder to build Builder
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
//Use the parameters of okHttpClient to build Builder, which is to pass the parameters of okHttpClient to Builder
Builder(OkHttpClient okHttpClient) {
/*
* . . . . . . . .
* */
}
//Set connection timeout
public Builder connectTimeout(long timeout, TimeUnit unit) {
connectTimeout = checkDuration("timeout", timeout, unit);
return this;
}
//Set the timeout for reading data
public Builder readTimeout(long timeout, TimeUnit unit) {
readTimeout = checkDuration("timeout", timeout, unit);
return this;
}
//Set the time-out for writing data
public Builder writeTimeout(long timeout, TimeUnit unit) {
writeTimeout = checkDuration("timeout", timeout, unit);
return this;
}
//Check whether the timeout is legal
private static int checkDuration(String name, long duration, TimeUnit unit) {
if (duration < 0) throw new IllegalArgumentException(name + " < 0");
if (unit == null) throw new NullPointerException("unit == null");
long millis = unit.toMillis(duration);
if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException(name + " too large.");
if (millis == 0 && duration > 0) throw new IllegalArgumentException(name + " too small.");
return (int) millis;
}
//Set the internal cache class of the cache class and leave the cache empty
void setInternalCache(InternalCache internalCache) {
this.internalCache = internalCache;
this.cache = null;
}
//Set cache and empty the reference of the internal cache class of cache class
public Builder cache(Cache cache) {
this.cache = cache;
this.internalCache = null;
return this;
}
//Set DNS
public Builder dns(Dns dns) {
if (dns == null) throw new NullPointerException("dns == null");
this.dns = dns;
return this;
}
//Set up a custom connection pool
public Builder connectionPool(ConnectionPool connectionPool) {
if (connectionPool == null) throw new NullPointerException("connectionPool == null");
this.connectionPool = connectionPool;
return this;
}
//Set whether to accept redirection
public Builder followRedirects(boolean followRedirects) {
this.followRedirects = followRedirects;
return this;
}
//Set whether reconnection is prohibited
public Builder retryOnConnectionFailure(boolean retryOnConnectionFailure) {
this.retryOnConnectionFailure = retryOnConnectionFailure;
return this;
}
//Set up a custom distributor
public Builder dispatcher(Dispatcher dispatcher) {
if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null");
this.dispatcher = dispatcher;
return this;
}
//Set the custom protocol. The custom protocol cannot include HTTP 1.0 and null, so Okhttp does not support HTTP 1.0 protocol
public Builder protocols(List<Protocol> protocols) {
// Create a private copy of the list.
protocols = new ArrayList<>(protocols);
// Validate that the list has everything we require and nothing we forbid.
if (!protocols.contains(Protocol.HTTP_1_1)) {
throw new IllegalArgumentException("protocols doesn't contain http/1.1: " + protocols);
}
if (protocols.contains(Protocol.HTTP_1_0)) {
throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols);
}
if (protocols.contains(null)) {
throw new IllegalArgumentException("protocols must not contain null");
}
if (protocols.contains(Protocol.SPDY_3)) {
protocols.remove(Protocol.SPDY_3);
}
this.protocols = Collections.unmodifiableList(protocols);
return this;
}
//Set custom connection rules
public Builder connectionSpecs(List<ConnectionSpec> connectionSpecs) {
this.connectionSpecs = Util.immutableList(connectionSpecs);
return this;
}
//Get a custom common interceptor
public List<Interceptor> interceptors() {
return interceptors;
}
//Setting up a custom common interceptor
public Builder addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
return this;
}
//Get a custom network interceptor
public List<Interceptor> networkInterceptors() {
return networkInterceptors;
}
//Setting up a custom network interceptor
public Builder addNetworkInterceptor(Interceptor interceptor) {
networkInterceptors.add(interceptor);
return this;
}
//Set up listeners for network start and end connections
Builder eventListener(EventListener eventListener) {
if (eventListener == null) throw new NullPointerException("eventListener == null");
this.eventListenerFactory = EventListener.factory(eventListener);
return this;
}
//To build OkHttpClient by building a good Builder is to pass the fields set by Builder to OkHttpClient
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
Main uses of OkHttpClient:
We can see from the source code that OkHttpClient is mainly used to configure the things you need in the process of network connection.
These include:
Timeout (XxxTimeout)
Interceptors
EventListener
Custom dispatcher
Whether to reconnect (retryOnConnectionFailure)
Custom connection pool, etc