关于OkHttp网上有很多分析的文章,本篇文章为个人对OkHttp的了解源码分析,自己复习使用,特此总结出来,okHttp为什么这么牛,为什么这么多人使用,以及框架有点,使用的到设计模式等等,从源码角度去分析,也会总结网上比较好的文章分析,欢迎一块探讨交流~
OkHttp 基本使用
本文源码分析基于3.14.2版本
implementation("com.squareup.okhttp3:okhttp:3.14.2")
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
//同步请求
// Response execute = call.execute();
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
OkHttp 请求过程
1.1 创建OkHttpClient 对象
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1);
代码省略 ....
//通过构造者模式初始化一些参数、配置
public OkHttpClient() {
this(new 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 = Util.platformTrustManager();
this.sslSocketFactory = newSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
if (sslSocketFactory != null) {
Platform.get().configureSslSocketFactory(sslSocketFactory);
}
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.callTimeout = builder.callTimeout;
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);
}
}
//简单介绍这些参数都是什么含义
public static final class Builder {
Dispatcher dispatcher; //调度器
/**
* 代理类,默认有三种代理模式DIRECT(直连),HTTP(http代理),SOCKS(socks代理)
*/
@Nullable Proxy proxy;
/**
* 协议集合,协议类,用来表示使用的协议版本,比如`http/1.0,`http/1.1,`spdy/3.1,`h2等
*/
List<Protocol> protocols;
/**
* 连接规范,用于配置Socket连接层。对于HTTPS,还能配置安全传输层协议(TLS)版本和密码套件
*/
List<ConnectionSpec> connectionSpecs;
//拦截器,可以监听、重写和重试请求等
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
/**
* 代理选择类,默认不使用代理,即使用直连方式,当然,我们可以自定义配置,
* 以指定URI使用某种代理,类似代理软件的PAC功能
*/
ProxySelector proxySelector;
//Cookie的保存获取
CookieJar cookieJar;
/**
* 缓存类,内部使用了DiskLruCache来进行管理缓存,匹配缓存的机制不仅仅是根据url,
* 而且会根据请求方法和请求头来验证是否可以响应缓存。此外,仅支持GET请求的缓存
*/
@Nullable Cache cache;
//内置缓存
@Nullable InternalCache internalCache;
//Socket的抽象创建工厂,通过createSocket来创建Socket
SocketFactory socketFactory;
/**
* 安全套接层工厂,HTTPS相关,用于创建SSLSocket。一般配置HTTPS证书信任问题都需要从这里着手。
* 对于不受信任的证书一般会提示
* javax.net.ssl.SSLHandshakeException异常。
*/
@Nullable SSLSocketFactory sslSocketFactory;
/**
* 证书链清洁器,HTTPS相关,用于从[Java]的TLS API构建的原始数组中统计有效的证书链,
* 然后清除跟TLS握手不相关的证书,提取可信任的证书以便可以受益于证书锁机制。
*/
@Nullable CertificateChainCleaner certificateChainCleaner;
/**
* 主机名验证器,与HTTPS中的SSL相关,当握手时如果URL的主机名
* 不是可识别的主机,就会要求进行主机名验证
*/
HostnameVerifier hostnameVerifier;
/**
* 证书锁,HTTPS相关,用于约束哪些证书可以被信任,可以防止一些已知或未知
* 的中间证书机构带来的攻击行为。如果所有证书都不被信任将抛出SSLPeerUnverifiedException异常。
*/
CertificatePinner certificatePinner;
/**
* 身份认证器,当连接提示未授权时,可以通过重新设置请求头来响应一个
* 新的Request。状态码401表示远程服务器请求授权,407表示代理服务器请求授权。
* 该认证器在需要时会被RetryAndFollowUpInterceptor触发。
*/
Authenticator proxyAuthenticator;
Authenticator authenticator;
/**
* 连接池
*
* 我们通常将一个客户端和服务端和连接抽象为一个 connection,
* 而每一个 connection 都会被存放在 connectionPool 中,由它进行统一的管理,
* 例如有一个相同的 http 请求产生时,connection 就可以得到复用
*/
ConnectionPool connectionPool;
//域名解析系统
Dns dns;
//是否遵循SSL重定向
boolean followSslRedirects;
//是否重定向
boolean followRedirects;
//失败是否重新连接
boolean retryOnConnectionFailure;
//回调超时
int callTimeout;
//连接超时
int connectTimeout;
//读取超时
int readTimeout;
//写入超时
int writeTimeout;
//与WebSocket有关,为了保持长连接,我们必须间隔一段时间发送一个ping指令进行保活;
int pingInterval;
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
/**
* 代理选择类,默认不使用代理,即使用直连方式,当然,我们可以自定义配置,以指定URI使用某种代理,类似代理软件的PAC功能
*/
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
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;
}
OkHttp 总的来说通过构造者模式,初始化一些例如调度器、拦截器等参数。
创建OkHttpClient 特别简单,直接new OkHttpClient ()对象出来或者是 OkHttpClient.Builder builder = new OkHttpClient().newBuilder();创建对象都可以。
1.2 创建OkHttpClient 对象
第二部创建Request 对象,下面看一下Request 对象到底做了什么
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;
private volatile @Nullable 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.tags = Util.immutableMap(builder.tags);
}
Request 类同样也是通过构造者模式来配置一些请求的参数,包含我们进行网络请求的地址,方法,请求头等。
1.3 创建Call对象 Call call = okHttpClient.newCall(request);我们来跟一下源码
Call call = okHttpClient.newCall(request);
通过okhttpClient的newCall(request);方法传入我们的请求reauest配置
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
newCall 方法返回了一个RealCall的真正的cal 接着跟踪
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.transmitter = new Transmitter(client, call);
return call;
}
通过此方法我们我们可以看到返回了RealCall 对象,Call 是一个接口,RealCall 是Call具体实现类,我们这个时候拿到了RealCall 对象
final class RealCall implements Call {
final OkHttpClient client;
/**
* There is a cycle between the {@link Call} and {@link Transmitter} that makes this awkward.
* This is set after immediately after creating the call instance.
*/
private Transmitter transmitter;
1.4 进行请求操作
1.4.1 我们通过拿到的call 对象直接调用call.execute();方法可以进行同步请求,但是一般情况下这个方法我们使用的很少,因为Android要求主线程不能执行耗时的操作否则容易出现ANR。
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
同步操作最终会调用getResponseWithInterceptorChain()这个方法,来返回我们的请求结果Response,我们接口返回的数据就封装在这个类里面,关于getResponseWithInterceptorChain();这个方法具体执行了什么操作,我们暂时不进行分析,稍后和异步同时进行分析。这个时候我们整个流程的同步操作流程就完成了。
1.4.2call.enqueue(new Callback() {}异步操作,我们来看看内部具体的实现:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
这个方法又通过okHttpClient中的dispatcher 调度器调了异步方法
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
此处又调用了promoteAndExecute()方法,接着跟
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
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;
}
此处出现了三个集合,来保存我们的请求 然后通过asyncCall.executeOn(executorService());方法来执行我们的请求
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
在此处我们发现了一个线程池,
public final class Dispatcher {
private int maxRequests = 64; //线程池最多同时执行64个请求
private int maxRequestsPerHost = 5; //相同host 最5个执行
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;
}
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
AtomicInteger callsPerHost() {
return callsPerHost;
}
void reuseCallsPerHostFrom(AsyncCall other) {
this.callsPerHost = other.callsPerHost;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
/**
* Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
* if the executor has been shut down by reporting the call as failed.
*/
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
通过模板模式来执行线程操作,最后我们会发现调用了这个方法getResponseWithInterceptorChain()来返回我们的结果,也就是说和同步操作一样,最终都是调用同一个方法来返回。区别在于异步OkHttp 默认为我们创建了线程池以及队列让我们进行异步请求。
到这基本上我们的同步异步流程就走完了。下篇文章我们分析getResponseWithInterceptorChain()这个方法到底执行了什么以及我们的请求到底是怎么请求的,怎么进行连接怎么返回的结果。以及OkHttp最核心的东西拦截器的作用。
网友评论