欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Okhttp3源码解析(3)-Call分析(整体流程)

程序员文章站 2022-10-04 14:48:36
### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析](https://www.jianshu.com/p/bf1d01b79ce7) [Okhttp3源码 ......
### 前言 前面我们讲了 [okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [okhttp3源码解析(1)-okhttpclient分析](https://www.jianshu.com/p/bf1d01b79ce7) [okhttp3源码解析(2)-request分析](https://www.jianshu.com/p/5a85345c8ea7) ### newcall分析 ##### call初始化 我们首先看一下在哪用到了call: ``` final call call = okhttpclient.newcall(request); ``` 想起来了吧?无论是get还是post请求 都要生成call对象,在上面我们发现call实例需要一个`okhttpclient`与`request`实例 ,我们先点进call类去看看: ``` public interface call extends cloneable { //请求 request request(); //同步 response execute() throws ioexception; //异步 void enqueue(callback responsecallback); //取消请求 void cancel(); //是否在请求过程中 boolean isexecuted(); //是否取消 boolean iscanceled(); call clone(); //工厂接口 interface factory { call newcall(request request); } } ``` 我们发现call是个接口, 并定义了一些方方法(方法含义在注释上)。 我们继续看`newcal()`方法 ``` @override public call newcall(request request) { return realcall.newrealcall(this, request, false /* for web socket */); } ``` 继续点击`newrealcall()`去: ``` private realcall(okhttpclient client, request originalrequest, boolean forwebsocket) { this.client = client; this.originalrequest = originalrequest; this.forwebsocket = forwebsocket; this.retryandfollowupinterceptor = new retryandfollowupinterceptor(client, forwebsocket); } 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.eventlistener = client.eventlistenerfactory().create(call); return call; } ``` 从代码中我们发现在`newrealcall()`中初始化了`realcall`,`realcall`中初始化了`retryandfollowupinterceptor` : - client: okhttpclient 实例 - originalrequest : 最初的request - forwebsocket :是否支持websocket通信 - retryandfollowupinterceptor 从字面意思来说, 是重试和重定向拦截器 ,至于它有什么作用我们继续往下看 ### 同步请求分析 ``` response response = call.execute(); ``` 我们点进`execute()`中查看: ``` @override public response execute() throws ioexception { synchronized (this) { if (executed) throw new illegalstateexception("already executed"); executed = true; } capturecallstacktrace(); eventlistener.callstart(this); try { client.dispatcher().executed(this); response result = getresponsewithinterceptorchain(); if (result == null) throw new ioexception("canceled"); return result; } catch (ioexception e) { eventlistener.callfailed(this, e); throw e; } finally { client.dispatcher().finished(this); } } ``` 从上面代码得知步骤: (1).通过 ` synchronized ` 保证线程同步,判断是否已经执行过 ,如果是直接抛异常 (2). `capturecallstacktrace();` 字面意思:捕获调用堆栈跟踪,我们通过源码发现里面涉及到了`retryandfollowupinterceptor` (3). ` eventlistener` 回调` callstart()` (4). `client.dispatcher().executed(this);` 看到了`dispatcher`是不是很熟悉?之前在分析`okhttpclient`初始化的时候遇到了,我们点击`executed()`方法进去: ``` synchronized void executed(realcall call) { runningsynccalls.add(call); } ``` 发现把我们传进来的`realcall`放到了`runningsynccalls`队列中,从字面意思来说就是正在运行的同步的调用队列中,为什么说是队列呢? : ``` private final deque runningsynccalls = new arraydeque(); ``` > deque即双端队列。是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,相比list增加[]运算符重载。 (5).我们回到`execute()`继续往下分析,剩下的代码我们提取出三行代码: - `equesr result = getresponsewithinterceptorchain();` 生成一个response 实例 - `eventlistener.callfailed(this, e);` :eventlistener的callfailed回调 - `client.dispatcher().finished(this);` :dispatcher实例的finished方法 不难看出,**`getresponsewithinterceptorchain()`**一定是此方法中的**核心**,字面意思是获取拦截器链的响应,这就明白了,就是**通过拦截器链处理后返回response** ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823173540636-96122427.png) ###### getresponsewithinterceptorchain() 分析 ``` response getresponsewithinterceptorchain() throws ioexception { // build a full stack of interceptors. list 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 (!forwebsocket) { interceptors.addall(client.networkinterceptors()); //网络拦截器 } interceptors.add(new callserverinterceptor(forwebsocket)); //调用服务器拦截器 interceptor.chain chain = new realinterceptorchain(interceptors, null, null, null, 0, originalrequest, this, eventlistener, client.connecttimeoutmillis(), client.readtimeoutmillis(), client.writetimeoutmillis()); return chain.proceed(originalrequest); } ``` 从上面代码不难看出, 对最初的request做了层层拦截,每个拦截器的原理我们放在以后的章节去讲, 这里就不展开了! 这里需要强调的一下 ` interceptors.addall(client.interceptors()); ` ,` client.interceptors()` 是我们自定义的拦截器 它是在哪定义的?如何添加?我们去okhttpclient类中发现: ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823173540985-1903691954.png) 可以通过初始化`okhttpclient`实例 ` .addinterceptor`的形式 添加。 ### 异步请求分析 ``` call.enqueue(new callback() { @override public void onfailure(call call, ioexception e) { log.d("okhttp_error",e.getmessage()); } @override public void onresponse(call call, response response) throws ioexception { gson gson=new gson(); log.d("okhttp_success",response.body().string()); } }); ``` 点击`enqueue()`查看: ``` @override public void enqueue(callback responsecallback) { synchronized (this) { if (executed) throw new illegalstateexception("already executed"); executed = true; } capturecallstacktrace(); eventlistener.callstart(this); client.dispatcher().enqueue(new asynccall(responsecallback)); } ``` (1).通过 ` synchronized ` 保证线程同步,判断是否已经执行过 ,如果是直接抛异常 (2). `capturecallstacktrace();` 字面意思:捕获调用堆栈跟踪,我们通过源码发现里面涉及到了`retryandfollowupinterceptor` (3). ` eventlistener` 回调` callstart()` (4). `client.dispatcher().enqueue(new asynccall(responsecallback));` 调用了`dispatcher.enqueue()`并传入了一个**`new asynccall(responsecallback)`**实例,点击**asynccall**查看: **asynccall 是realcall的内部类!** ``` final class asynccall extends namedrunnable { private final callback responsecallback; asynccall(callback responsecallback) { super("okhttp %s", redactedurl()); this.responsecallback = responsecallback; } string host() { return originalrequest.url().host(); } request request() { return originalrequest; } realcall get() { return realcall.this; } @override protected void execute() { boolean signalledcallback = false; try { 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 { eventlistener.callfailed(realcall.this, e); responsecallback.onfailure(realcall.this, e); } } finally { client.dispatcher().finished(this); } } } ``` `asynccall`继承了`namedrunnable` ,我们看下`namedrunnable`是什么: ``` public abstract class namedrunnable implements runnable { protected final string name; public namedrunnable(string format, object... args) { this.name = util.format(format, args); } @override public final void run() { string oldname = thread.currentthread().getname(); thread.currentthread().setname(name); try { execute(); } finally { thread.currentthread().setname(oldname); } } protected abstract void execute(); } ``` 原来`namedrunnable` 实现了`runnable` 接口 是个线程类,在`run()`中 添加了抽象的`execute();`方法,看到这里 我们应该有一个反应,那就是**asynccall中具体的execute()应该在子线程执行** 我们继续分析,`client.dispatcher().enqueue(new asynccall(responsecallback));` 点击进入enqueue(): ``` synchronized void enqueue(asynccall call) { if (runningasynccalls.size() (), util.threadfactory("okhttp dispatcher", false)); } return executorservice; } ``` 其实就是生成了executorservice 实例,这就明白了,`asynccall `实例放入线程池中执行了! 如果不满足上面的请求数等条件: ``` readyasynccalls.add(call); ``` 就会被添加到一个等待就绪的异步请求队列中,目的是什么呢??? 当然是等待时机再次添加到runningasynccalls中并放入线程池中执行,这块逻辑在 `asynccall `类中的 `execute() ` 至于原因我们继续往下看! ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823173541531-1963303270.png) 刚才我们说了,如果条件满足, `asynccall `实例就会在线程池中执行(.start),那我们直接去看run()中的 `execute() ` : ``` @override protected void execute() { boolean signalledcallback = false; try { 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 { eventlistener.callfailed(realcall.this, e); responsecallback.onfailure(realcall.this, e); } } finally { client.dispatcher().finished(this); } } ``` 上面代码中得知, 首先通过层层拦截器链处理生成了`response`;然后通过一系列的判断,`responsecallback`进行`onresponse`与`onfailure`回调,最后调用的`dispatcher.finifshed()` 这里需要注意的是 **这里的`dispatcher.finifshed(this)`与同步中的`dispatcher.finifshed(this)`不一样** 参数不同。 ``` /** used by {@code asynccall#run} to signal completion. */ void finished(asynccall call) { finished(runningasynccalls, call, true); } ``` 我们继续看具体的finifshed()方法: ``` private void finished(deque calls, t call, boolean promotecalls) { int runningcallscount; runnable idlecallback; synchronized (this) { if (!calls.remove(call)) throw new assertionerror("call wasn't in-flight!"); if (promotecalls) promotecalls(); runningcallscount = runningcallscount(); idlecallback = this.idlecallback; } if (runningcallscount == 0 && idlecallback != null) { idlecallback.run(); } } ``` 在线程同步的情况下 执行了`promotecalls();`: ``` private void promotecalls() { if (runningasynccalls.size() >= maxrequests) return; // already running max capacity. if (readyasynccalls.isempty()) return; // no ready calls to promote. for (iterator i = readyasynccalls.iterator(); i.hasnext(); ) { asynccall call = i.next(); if (runningcallsforhost(call) = maxrequests) return; // reached max capacity. } } ``` 经过一系列的判断, 对等待就绪的异步队列进行遍历,生成对应的`asynccall `实例,并添加到runningasynccalls中,最后放入到线程池中执行! 这里就是我们上面说到的等待就绪的异步队列如何与runningasynccalls对接的逻辑。 ### 总结 ##### 同步请求流程: - 生成`call`实例realcall - `dispatcher.executed()`中的`runningsynccalls` 添加realcall到此队列中 - 通过 `getresponsewithinterceptorchain()` 对request层层拦截,生成response - 通过`dispatcher.finished()`,把call实例从队列中移除,返回最终的response ##### 异步请求流程: - 生成一个`asynccall(responsecallback)`实例(实现了runnable) - `asynccall`实例放入了`dispatcher.enqueue()`中,并判断`maxrequests` (最大请求数)`maxrequestsperhost`(最大host请求数)是否满足条件,如果满足就把`asynccall`添加到`runningasynccalls`中,并放入线程池中执行;如果条件不满足,就添加到等待就绪的异步队列,当那些满足的条件的执行时 ,在`dispatcher.finifshed(this)`中的`promotecalls();`方法中 对等待就绪的异步队列进行遍历,生成对应的`asynccall `实例,并添加到`runningasynccalls`中,最后放入到线程池中执行,一直到所有请求都结束。 至此okhttp整体流程就分析完了, 下一篇会分块去分析,希望对大家有所帮助... ![](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823173541905-1601958458.png) 大家可以关注我的微信公众号:「秦子帅」一个有质量、有态度的公众号! ![公众号](https://img2018.cnblogs.com/blog/1312938/201908/1312938-20190823173542046-1151555749.jpg)