开发项目很久了,一直在用Okhttp,今天下午时间充裕,却发现对okhttp理解少之又少。对它说不出什么所以然来。那就战吧,苦一下自己看源码去咯。
绝对以小白视角看源码,我会你会大家都会,都能懂源码的。以后去面试。照着说准没错!
首先我们看一下Okhttp的正常请求流程,以便我们在源码中找到入口
mOkHttpClient=new OkHttpClient();
Request.Builder requestBuilder = new Request.Builder().url("http://www.baidu.com");
//可以省略,默认是GET请求
requestBuilder.method("GET",null);
Request request = requestBuilder.build();
Call mcall= mOkHttpClient.newCall(request);
mcall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (null != response.cacheResponse()) {
String str = response.cacheResponse().toString();
Log.i("wangshu", "cache---" + str);
} else {
response.body().string();
String str = response.networkResponse().toString();
Log.i("wangshu", "network---" + str);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
}
});
}
});
}
1,入口处我们看到 – mOkHttpClien = new OkhttpClient(); 初始化一系列数据,暂且不管,后面哪些在我们看源码的进程上的话我们再分析。
public OkHttpClient() {
this(new Builder());
}
//Builder 是okhttpClient 中的一个内部类
public Builder() {
//一会我们将会用到dispatcher
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
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;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
2, 初始化了一个RequestBuilder reBuilder = new Request.Builder().url(“http://www.baidu.com“);
public Builder() {
//默认的就是get,因此前面你能省略get请求
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(HttpUrl url) {
if (url == null) throw new NullPointerException("url == null");
this.url = url;
return this;
}
3,Url准备就绪,那就开始进入正文了
Request request = requestBuilder.build();
Call mcall= mOkHttpClient.newCall(request);
重要的部分在newCall();
@Override
public Call newCall(Request request) {
//返回一个RealCall,Call是个interface
return new RealCall(this, request);
}
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
4,走到这,我们看出来了,调用enquene的是readcall,那就继续看他的方法是怎么回事
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
//1,这里又将问题抛回到OkHttpClient的对象了
//2.执行了一个异步的call
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
// 这个异步的call也暂时只记录这个请求回调,无关大事,我们继续走
private AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl().toString());
this.responseCallback = responseCallback;
}
5,我们看到有dispatcher来执行enquene了,感觉好麻烦,传到okhttp初始化的时候了
public final class Dispatcher {
//最大并发请求数
private int maxRequests = 64;
//每个主机最大请求数
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
//消费者线程池 每次进来要么传进来一个,要么自己进行初始化,保证了此对象一直存在
private ExecutorService executorService;
/** 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<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
6,再继续看他的enqueue
synchronized void enqueue(AsyncCall call) {
//当前运行的异步请求队列数小于64 运行的请求主机数小于5
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
// 这里保证了 线程池绝对初始化了
executorService().execute(call);
} else {
// 否则的话再把请求增加到 准备请求队列
readyAsyncCalls.add(call);
}
}
7,这里我们看到将call放到线程池去执行了,还记得吧,放入的是AsyncCall,那我们去看AsyncCall执行的方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
// 得到Response了!! 那我就看这一步了,到底做了什么,就返回给我们数据了
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 {
// 回调了。。。。失败
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
8,这个方法好像很麻烦啊,好吧我们先看最后简单,调用的这个finsh这个方法是什么意思
synchronized void finished(AsyncCall call) {
//运行的请求队列移除这个请求,失败的话抛异常
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
private void promoteCalls() {
//当前运行的请求数 是否太大
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
//准备请求队列是否为空
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
// 对准备请求队列遍历 加入到请求队列,并执行
// 是不是发觉和前面的执行重叠了 走完了??
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
9,NO! NO! NO! 访问网络的的流程我们走完了,但是怎么会偶去到数据的过程,我们也还是能看下最好。当然,你只为了了解okhttp的访问流程就不太需要后面的细节了。
// 这里它凭什么就能得到Response
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
//一大堆的拦截者 产生了一个拦截的Chain ,它看来是关键咯,执行了请求
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
10,哎,看到这里我们发觉其实明白表层逻辑真没什么难度,就是麻烦,学习思想嘛,慢慢看下去。 进入到 RealInterceptorChain的proceed方法中去了
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !sameConnection(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 关键的在这里了 从拦截集合中取出当前请求的拦截,去执行方法了! 这里可能取出多个拦截器,还记得前面一直向一个集合放拦截器吗,对就是那里 报应来了,放的多也就取得多了!
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
//有个疑问是不,要是拦截器太多会怎么办, 这里会阻塞的,当前拦截器会等待下一个拦截器执行完毕再返回!拦截器嘛,大多都是移除或者转换请求或者响应的头部信息。
11,这就麻烦了,拦截这里源码可是很多的
暂时先看到这里吧,后面这留个一个个讲的话太长了,本篇也够了!下回的话分第二篇吧。