【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
OKHttp源码解读
本次分享主要目标
- 1.大概流程解读,同步流程,异步流程
- 2.Interceptor简读
一、OKHttp的简单使用
private String get(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
private void useOkHttp() throws IOException {
//1.创建OkHttpClient对象
OkHttpClient okhttp = new OkHttpClient.Builder()
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
//2.创建请求对象Request
Request request = new Request.Builder()
.url("url")
.addHeader("key","value")
.get()//设置请求方式是get
.build();
Call call = okhttp.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody body = response.body();
String string = body.string();
}
});
}
以上是OKHttp很简单的两个用法,一个是同步的,一个是异步的。
二、回顾Retrofit源码与OKhttp的初始化
- Rerofit的初始化
- ServiceMethon的初始化
- 调用OKHttp
- 装饰器 adapt的使用
OKHttp与Retrofit都是同一帮人写的,所以写法是类似的。
Builder重度使用,OKHttpCient与Retrofit的作用类似。
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
final Dispatcher dispatcher;
final @Nullable Proxy proxy;
final List<protocol> protocols;
final List<connectionspec> connectionSpecs;
final List<interceptor> interceptors;
final List<interceptor> networkInterceptors;
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;
final CookieJar cookieJar;
final @Nullable Cache cache;
final @Nullable InternalCache internalCache;
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
final Dns dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
final int callTimeout;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;
请求过程中用到的各种设置都可以从这里拿到,Retrofit的next方法是不是还有印象,后面的各种方法都是有retrofit的参数传进去,获取初始化参数。
三、执行过程简析
Call call = okhttp.newCall(request);
call.enqueue
call.execute
这个是先拿到一个request,然后excute或者enqueue
1.我们先分析同步的代码流程
@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);
}
}
@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));
}
client.dispatcher().executed(this);
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
我们总结总结同步的流程
- RealCall.excute
- client.dispatcher().executed
- RealCall.getResponseWithInterceptorChain
- client.dispatcher().finished;
同步执行的时候,runningSyncCalls 进行了添加删除用作记录,目前没有数量控制,也没有线程调度什么。
看到这个Call,有没有想到Retrofit里的Call?
- Retrofit Call接口,OKHttpCall
- OKHttp里也是有个Call接口,RealCall,作为他的实现类,还有一个AsyncCall,但是这个不是Call的实现类,复制RealCall做异步使用的。
2.异步流程解析
RealCall.enqueue
@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));
}
Dispatcher.enqueue
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();
}
Dispatcher.promoteAndExecute
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
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!
}
}
}
AsyncCall.execute->RealCall.getResponseWithInterceptorChain()->AsyncCall.responseCallback
@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);
}
}
我们总结总结异步的流程
> 1. RealCall.enqueue > 2. Dispatcher.enqueue > 3. Dispatcher.promoteAndExecute > 4. AsyncCall.executeOn > 5. AsyncCall.execute > 6. RealCall.getResponseWithInterceptorChain > 7. AsyncCall.responseCallback
从流程上来看的话,不管是同步异步实际请求都是调用
RealCall.getResponseWithInterceptorChain
只是异步请求Dispatcher 做了线程管理,这块内容下次再做分享
三、Interceptor简析
getResponseWithInterceptorChain的实现
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
这里的核心是
- interceptors.add
- Response response = chain.proceed(originalRequest);
添加拦截器,执行拦截器。
拦截器的执行采用的是递归原理,理解了递归原理的话,拦截器这块就没什么内容了,就是解读各个拦截器的实现。
我们看下一个简单的递归例子
function Recursion(depth) {
console.log('抱着');
if (!depth) {
console.log('我的小鲤鱼')
} else {
Recursion(--depth); // 递归调用
}
console.log('的我');
}
console.log('吓得我抱起了');
Recursion(2)
日志打印出来
- 吓得我抱起了
- 抱着
- 抱着
- 抱着
- 我的小鲤鱼
- 的我
- 的我
- 的我
递归的特点
- 递归结束的条件
- 执行顺序,前置的按照顺序从上往下执行,结果是从下往上
这里是不是可以理解,每个interceptor都能拿到网络请求后的response结果了,因为最后一个拿到的response,然后从下往上每个都能拿到了。
Interceptor的原理明白了吗?
也就是开始被执行的类request的信息是做少的,越执行reqeust信息越多,response,则是最后被执行的的是最原始的,然后被修改添加的越多。
我们再来学习下Interceptor的1个知识点
- interceptor与networkInterceptor的区别
- RetryAndFollowUpInterceptor代码解读
通过 addInterceptor() 方法添加的拦截器是放在最前面的。而通过 addNetworkInterceptor() 方法添加的网络拦截器,则是在非 WebSocket 请求时,添加在 ConnectInterceptor 和 CallServerInterceptor 之间的。
addInterceptor(应用拦截器):
- 不需要担心中间过程的响应,如重定向和重试.
- 总是只调用一次,即使HTTP响应是从缓存中获取.
- 观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
- 允许短路而不调用 Chain.proceed(),即中止调用.
- 允许重试,使 Chain.proceed()调用多次 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ addNetworkInterceptor(网络拦截器):
- 能够操作中间过程的响应,如重定向和重试.
- 当网络短路而返回缓存响应时不被调用.
- 只观察在网络上传输的数据.
- 携带请求来访问连接.
RetryAndFollowUpInterceptor
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, transmitter, requestSendStarted, request)) throw e;
continue;
} finally {
// The network call threw an exception. Release any resources.
if (!success) {
transmitter.exchangeDoneDueToException();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Exchange exchange = Internal.instance.exchange(response);
Route route = exchange != null ? exchange.connection().route() : null;
Request followUp = followUpRequest(response, route);
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
closeQuietly(response.body());
if (transmitter.hasExchange()) {
exchange.detachWithViolence();
}
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
request = followUp;
priorResponse = response;
}
}
这里有个比较关关键的一点
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
response = realChain.proceed(request, transmitter, null);
while(true) 这里是跟其他interceptor不一样的地方,对于重定向大家有没有了解?
退出while的条件
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
一个是返回后没有再重定向了,另外一个则是重定向次数超过了阈值
注意点
重定向执行的时候,是没有再调用Interceptor,但是netInterceptor还是被调用的。
本次分享到此结束,下次详解,dispatch与其他interceptor </interceptor></asynccall></asynccall></interceptor></interceptor></connectionspec></protocol>
来源:oschina
链接:https://my.oschina.net/u/2264711/blog/3149163