Okhttp-v4.9.0源码流程分析
2020-10-22 15:29:59 0 举报
登录查看完整内容
Okhttp网络请求源码分析
作者其他创作
大纲/内容
14:proceed
41:createRequestBody
35:writeRequestHeaders
3:intercept
21:kickCoordinator
12:proceed
40:createRequestBody
RealCall
45:emitFrame
25:runTask
18:execute
26:Task/runOnce
BridgeInterceptor
49:readResponseHeaders
19:schedule
11:intercept
返回RequestBodySink对象
返回ExchangeCodec对象(Http1ExchangeCodec/Http2ExchangeCodec)
返回Response对象
34:intercept
29:readData
3:enqueue
16:start
OkhttpClient
RequestBody
返回自定义FramingSink对象,网络请求输出通道
15:intercept
ConnectInterceptor
16:proceed
18:proceed
6:intercept(中间省略多个拦截器)
31:receiveData
11:connect
返回ResponseBody对象
异步加载流程说明:1、OkHttpClient类作为okhttp网络请求入口类,内部实现一个Builder内部类,采用了建造者设计模式;可以直接实例化采用默认的设置配置,也可以通过Builder内部类来实例化OkhttpClient对象,通过建造者对象实例可以自定义配置参数,如连接时长、超时时长以及拦截器等等;这里采用直接实例化来进行分析,OkhttpClient对象只做参数设置等,无具体的操作,是webSocket长连接与普通网络数据请求(短连接)入口,此处分析普通数据请求(短连接)过程, 调用newCall()方法并且传入请求者Request对象, 请求者对象是设置请求参数的携带对象, 包括请求url、请求方式、请求体、请求头等等;然后会初始化RealCall对象, 该对象是请求的实际实现对象, 管理网络请求具体逻辑,包括网络连接、请求、响应和流操作2、初始化RealCall对象, 将OkhttpClient与Request对象传入3、调用RealCall对象的execute()方法, 该方法不传回调接听接口代表网络同步请求, 传一个Callback监听接口对象代表采用网络异步请求;这里分析异步请求, 首先会判断是否在执行中,然后调用callStart()方法来追堆栈信息, 最后调用Dispatcher对象的enqueue()方法, Dispatcher对象是线程池管理类, 管理异步请求,创建一个AsyncCall对象,该对象实现Runnable接口, 运行在线程池中,传入Dispatcher对象的enqueue()方法4、调用Dispatcher对象的enqueue()方法,Dispatcher对象是OkhttpClient对象创建是创建的, 同时在该类中创建了一个线程池executorService变量;将传入的AsyncCall对象加入可读异步调用span style=\"font-size: inherit;\
10:proceed
2:RealCall
52:openResponseBody
4:enterNetworkInterceptorExchange
8:AsyncCall/run
9:findHealthyConnection
23:run
TaskQueue
32:newCodec
17:newQueue
返回Source对象
13:connectSocket
Http2Stream
44:FramingSink/write
Dispatcher
6:AsyncCall/executeOn
9:getResponseWithInterceptorChain
1:newCall
13:intercept
TaskRunner
50:readResponseHeaders
47:data
43:writeTo
53:openResponseBodySource
19:intercept
17:intercept
返回Response.Builder对象
RealInterceptorChain
4:enqueue
CallServerInterceptor
54:ResponseBodySource
Http2Connection
27:block(实际调用是ReaderRunnable类的invoke())
10:findConnection
5:promoteAndExecute
28:nextFrame
CacheInterceptor
8:find
初始化网络连接通道:1、从第一部分流程第9步知道, 此时才是真正进入网络请求实现入口, Okhttp定义了五个默认拦截器, 其中网络连接通道管理ExchangeFinder(管理socket连接对象以及初始化socket连接)对象是在RetryAndFollowUpInterceptor拦截器中创建的;然后在ConnectInterceptor拦截器中创建Socket网络连接通道并且创建连接具体协议(Http1ExchangeCodec/Http2ExchangeCodec), 创建一个Exchange对象管理ExchangeFinder对象以及连接具体协议对象, 也就是管理网络请求与响应; 当Socket通道与连接协议创建完成后会像网络通道发起初始前置信息与读取前置信息2、调用RealInterceptorChain对象proceed()方法, 是一个过渡方法, 主要是分发各个拦截器, 最后调用intercept()方法进入具体的拦截器3、进入RetryAndFollowUpInterceptor拦截器中, 首先调用RealCall对象的enterNetworkInterceptorExchange()方法初始化服务器连接器的查询管理对象ExchangeFinder,ExchangeFinder对象管理socket连接对象以及初始化socket连接;然后调用proceed()方法进入下一个拦截器4、调用RealCall对象的enterNetworkInterceptorExchange()方法初始化服务器连接器的查询管理对象ExchangeFinder,ExchangeFinder对象管理socket连接对象以及初始化socket连接5、调用RealInterceptorChain对象proceed()方法进入下一个拦截器, 此处略过中间几个拦截器然后进入ConnectInterceptor拦截器6、此处略过中间几个拦截器然后进入ConnectInterceptor拦截器,调用RealCall对象initExchange()方法获取Socket对象以及创建连接具体协议(Http1ExchangeCodec/Http2ExchangeCodec), 创建一个Exchange对象管理ExchangeFinder对象以及连接具体协议对象,也就是管理网络请求与响应7、获取具体协议连接对象(Http1ExchangeCodec或者Http2ExchangeCodec, 基于Socket连接, 针对不同版本的http), 此处采用Http2ExchangeCodec对象来分析网络请求流程;初始化一个网络链接交换器,用于连接服务器以及数据请求,最后返回这个交换器8、此处分析Socket对象创建过程以及首次连接时是如何第一次发送与接收前置数据; 此时调用到ExchangeFinder对象的find()方法, 由于Socket对象是一个可重用对象(针对相同的host),调用findHealthyConnection获取一个可正常使用的Socket;然后调用RealConnection对象newCodec()方法获取具体连接协议Http2ExchangeCodec对象并且返回9、通过循环不断读取可用的Socket对象, Socket对象封装在RealConnection对象中, 遍历获取到的RealConnection对象判断Socket对象是否连接良好, 获取到可用RealConnection对象并且返回; RealConnection对象是Socket对象创建、协议定义、定义中间交接流对象以及证书ssl等真正实现类, 同时是Socket连接成功进行初始数据交互的实现类;RealConnection对象保存在连接池中, 连接池大小定义为5个数量级,确保可以循环利用避免频繁创建,其中保活数量为5个数量级, 保活原理是定时心跳连接机制以及连接机制, 通过TaskRunner线程池任务执行器进行连接对象管理,如果超过了“保持活动”限制或“空闲连接”限制,则驱逐了最长的空闲连接,也就是是停止连接做回收处理10、调用findConnection()方法, 此处是真正获取RealConnection对象的实现(也就是获取Socket连接对象),首先通过获取RealCall类的缓存connection变量进行判断是否与当前连接URL连接路由一致并且判断是否释放, 一致且未释放则重复利用,不新创建; 然后当不满足路由一致或者已经释放或者RealCall类的缓存connection变量存在,那么从连接池里遍历获取一致的连接对象, 有则返回,否则创建新的连接对象RealConnection;最后将完好的RealConnection对象缓存到RealCall类的缓存connection变量变量中以及连接池中11、当第一次连接,那么会创建RealConnection对象来实例化Socket连接, 调用到RealConnection对象的connect()方法,首先进行URL判断与协议判断, 判断路由是否通过HTTP代理隧道HTTPS,是的话调用connectTunnel()方法进行Socket创建连接, 否则为一般HTTP协议则直接创建Socket即可, 然后调用establishProtocol()方法建立连接协议对象(http1/http2或者其他),进行初始网络请求以响应12、此处分析代理隧道HTTPS, 调用到connectTunnel()方法, 首先创建代理通道, 隧道请求中的所有内容均未加密地发送到代理服务器,因此隧道仅包括最小的标头集,这样可以避免将未加密的潜在敏感数据(例如HTTP cookie)发送到代理;然后通过一个循环创建socket连接并且判断当前连接通过是否创建成功, 成功退出循环, 退出循环代表Socket对象创建完成13、调用connectSocket()方法进行Socket创建并且连接,获取source读取通道源流对象(读取数据)以及获取sink写入通道流对象(发送数据)14、当建立Socket连接后, 则继续创建具体协议连接类型(http1/http2或者其他),此处分析Http2, 则调用到startHttp2()方法15、调用startHttp2()方法, 首先建立一个Http2Connection连接托管对象, 管理Socket连接的读写通道, 在Http2Connection对象中建立一个Http2Writer对象并且传入Socket连接sink写入通道流对象(发送数据), Http2Writer对象为发送数据具体实现与封装,同时创建了一个Http2Reader对象并且传入Socket连接source读取通道源流对象(读取数据),Http2Reader对象为读取数据的具体实现与封装,将创建好的Http2Reader对象传入一个创建的ReaderRunnable对象中, ReaderRunnable对象, 是一个运行任务类, Socket连接读取数据是在独立的TaskRunner线程池任务执行器中进行16、当Http2Connection连接托管对象创建成功后, 则会启动Socket连接的第一次请求和响应, 调用start()方法,首先发送第一次连接请求;创建一个TaskRunner线程池任务执行器, 然后在TaskRunnerr线程池任务执行器中创建一个TaskQueue任务队列, 调用TaskQueue任务队列对象的execute()方法将ReaderRunnable对象传入进行读取连接通道流数据17、在TaskRunnerr线程池任务执行器中创建一个TaskQueue任务队列18、调用TaskQueue任务队列对象的execute()方法, 创建一个Task对象任务, 在Task对象runOnce()方法调用ReaderRunnable对象的 invoke()回调方法真正执行读取数据19、将创建好的Task对象传入schedule()方法,调用scheduleAndDecide()方法将Task对象加入队列列表中, 然后调用TaskRunnerr线程池任务执行器的kickCoordinator()在线程池中执行任务20、调用scheduleAndDecide()方法将Task对象加入队列列表中,队列列表任务存放是按照时间进行顺序排列, 需要优先执行的任务会排列到队列列表前部21、调用到TaskRunnerr线程池任务执行器的kickCoordinator()方法, 在TaskRunnerr线程池任务执行器创建之时会创建一个Runnable对象, 线程池执行的就是该Runnable对象进而执行Task任务,首先会将任务存入readyQueues读取队列列表中,然后判断是否有任务在执行, 无的情况下则调用线程池execute()方法执行任务22、调用线程池execute()方法执行TaskRunnerr线程池任务执行器Runnable对象, 回调到Runnable对象对象的run()方法23、执行线程池回调到Runnable对象对象的run()方法,此处采用一个无限循环用于执行任务, 读取Socket通道的数据,首先获取获取需要执行的任务;然后调用runTask()方法执行任务24、调用awaitTaskToRun()从readyQueues读取队列列表中获取需要执行的任务25、调用runTask()方法执行任务, 这个是一个过渡方法, 最终调用到TaskQueue任务队列Task对象的runOnce()方法执行读取Socket连接数据26、调用到TaskQueue任务队列Task对象的runOnce()方法执行Http2Connection连接托管对象内部类ReaderRunnable对象的invoke()回调方法,进行Socket连接数据读取27、执行Http2Connection连接托管对象内部类ReaderRunnable对象的invoke()回调方法, 首先调用Http2Reader对象的readConnectionPreface进行第一次数据读取; 然后通过无限循环调用Http2Reader对象的nextFrame()不断读取Socket连接通道的数据28、调用Http2Reader对象的nextFrame()方法, 判断读取Socket连接通道数据的类型, 通过Socket连接source对象来读取数据, 此处分析读取数据,也就是调用readData()方法29、调用readData()方法, 此方法为一个过渡方法, 将读取的数据转发出去(如:Http2Connection/ReaderRunnable的data方法), 此时调用到Http2Connection/ReaderRunnable的data方法30、调用到Http2Connection/ReaderRunnable的data方法, 首先判断流数据是否是HTTP/2数据流,是就延迟发送读取的数据; 然后获取自定义的Http2Stream管理数据流对象(对象的创建在CallServerInterceptor拦截器中,也就是发送请求头的时候会创建一个对应Http2Stream对象, 用于接收Socket连接流,通过Http2Stream代理对象读取到响应数据,后面会分析), 刚刚创建Socket连接进行第一次请求与响应时, 此时Http2Stream管理数据流对象并没有创建, 也就是Http2Stream管理数据流对象存在是则会调用writeSynResetLater()方法进行读写同步延迟操作, 通过TaskRunnerr线程池任务执行器进行管理操作,直到CallServerInterceptor拦截器初始化成功并且创建出Http2Stream管理数据流对象(该对象创建会创建自定义FramingSink写入通道流对象(发送数据)以及FramingSource读取通道源流对象(读取数据), 通过这两个对象间接处理发送与响应数据), 最后调用Http2Stream管理数据流对象的receiveData()方法将Socket连接获取source读取通道源流对象(读取数据)写入FramingSource对象中进行响应数据间接管理31、调用Http2Stream管理数据流对象的receiveData()方法将Socket连接获取source读取通道源流对象(读取数据)写入FramingSource对象中进行响应数据间接管理,FramingSource对象是Http2Stream管理数据流对象创建是创建的, 间接管理Socket连接通道数据源32、回到第8步, 当RealConnection对象与Http2Connection对象完成并且初始化网络连接, 返回RealConnection对象并且调用该对象newCodec()方法,由于创建了Http2Connection对, 此时在RealConnection对象中http2Connection变量不为空, 因此创建Http2ExchangeCodec对象将RealConnection对象与Http2Connection对象传入, Http2ExchangeCodec对象作为连接器管理对象, 对外提供请求响应接口,是一个中间管理器,最后将Http2ExchangeCodec对象返回RealCall对象中。 到此初始化网络连接器完成数据的请求与响应:33、当初始化网络连接完成, 是在ConnectInterceptor拦截器中完成, 此时调用RealInterceptorChain连接链对象的proceed()方法进入下一个拦截器, 最后在拦截器列表中获取到CallServerInterceptor拦截器调用intercept()方法,此时进行真正的网络请求交互34、执行到CallServerInterceptor拦截器intercept()方法,此处是进行真正的网络交互实现, 首先是请求执行逻辑分为三步:发送请求头(在此处创建Http2Stream管理数据流对象, 用于代理Socket连接通道流管理)、发送请求体(存在请求体的情况下)以及关闭请求;然后是响应逻辑操作分为三步:接收头部响应信息、结束接收响应以及获取响应数据(通过Http2Stream管理数据流对象获取, 由于网络初始化连接完成时会有线程池任务不断的读取Socket连接通道流源数据,并且不断检测Http2Stream对象是否已经创建,当在发送请求头时创建Http2Stream对象后读取响应线程池任务检测到Http2Stream对象不为空(线程池执行为独立线程, 执行检测为毫秒级),将Socket连接通道响应流源对象写入Http2Stream对象的FramingSource对象进行代理管理)35、调用Exchange交换器的writeRequestHeaders()方法进行发送请求头信息, 该方法是一个过渡方法, 正在的实现是调用Http2ExchangeCodec对象的writeRequestHeaders()方法36、调用Http2ExchangeCodec对象的writeRequestHeaders()方法,判断Http2Stream管理数据流对象是否创建, 未创建则调用Http2Connection对象newStream()方法创建一个Http2Stream对象, Http2Stream对象是一个间接管理响应流源数据对象37、调用Http2Connection对象newStream()方法创建一个Http2Stream对象, 该对象是一个过渡方法,调用到newStream()方法重载方法38、首先创建一个Http2Stream对象用于管理服务器源数据流, 将创建的Http2Stream对象保存到streams的Map集合中; 然后调用Http2Writer对象headers()方法发送请求头部信息39、调用Http2Writer对象headers()方法发送请求头部信息, 到此发送请求头部完成40、调用Exchange交换器的createRequestBody()方法创建一个输出的通过流的缓存区Sink对象(网络请求的输出数据流通道, 将请求数据写入通道既是发送数据给服务器), Sink对象持有Socket连接通道sink对象的直接引用41、调用调用Http2ExchangeCodec对象的createRequestBody()方法获取到一个自定义Sink对象, 过渡方法, 最终调用Http2Stream对象获取到FramingSink对象(持有Socket连接通道sink对象的直接引用), 42、调用Http2Stream对象的getSink()方法,获取到FramingSink对象(持有Socket连接通道sink对象的直接引用)返回Exchange交换器中, 然后创建RequestBodySink对象管理FramingSink对象43、当有请求数据是调用RequestBody对的writeTo()方法发送请求数据,该方法为过渡方法,最后调用到FramingSink对象的write()方法发送请求数据44、调用到FramingSink对象的write()方法,通过一个循环调用emitFrame()方法不断发送字节数据45、调用emitFrame()方法, 该方法是一个过渡方法, 调用Http2Connection对象的writeData()方法发送数据46、调用Http2Connection对象的writeData()方法, 判断Socket连接通道是否是可在使用状态, 然后调用Http2Writer对象的data()方法发送请求数据47、调用Http2Writer对象的data()方法, 该方法是一个过渡方法, 调用dataFrame()完成发送请求数据48、最终通过Socket对象的sink对象通道, 用于将数据写入通道中(发送数据)。 到此发送请求数据完成, 最后调用Exchange交换器的finishRequest()关闭输出流通道, 结束发送动作49、请求完成后则开始接收响应数据, 调用到Exchange交换器的readResponseHeaders()方法读取响应头部信息, 该方法是一个过渡方法, 最终调用到Http2ExchangeCodec对象的readResponseHeaders()方法50、调用到Http2ExchangeCodec对象的readResponseHeaders()方法, 首先通过Http2Stream对象获取到响应头信息, 调用readHttp2HeadersList()方法进行响应头封装51、调用readHttp2HeadersList()方法进行响应头封装成Response.Builder对象并且返回, 此时接收响应头信息完成52、调用Exchange交换器的openResponseBody()方法, 首先调用Http2ExchangeCodec对象的openResponseBodySource()方法获取到数据源对象(Socket连接的数据流源已经写入Http2Stream对象的FramingSource中),然后创建ResponseBodySource对象封装FramingSource对象,最后创建RealResponseBody对象来管理响应数据53、调用Http2ExchangeCodec对象的openResponseBodySource()方法获取到数据源对象(Socket连接的数据流源已经写入Http2Stream对象的FramingSource中)54、创建ResponseBodySource对象封装FramingSource对象55、创建RealResponseBody对象来管理响应数据并且返回,最后封装到Response对象中, 通过调用Response对象的body.string()来获取响应数据。 到此网络响应完成
Http2Reader
14:establishProtocol
2:proceed
48:dataFrame
一、网络请求流程
ExchangeFinder
30:data
5:proceed
51:readHttp2HeadersList
7:AsyncCall/execute
Http2Writer
返回自定义Sink对象
22:execute
1:getResponseWithInterceptorChain
36:writeRequestHeaders
55:RealResponseBody
15:startHttp2
20:scheduleAndDecide
Exchange
1、异步网络加载流程(总体流程):val client = OkHttpClient()val request = Request.Builder() .url(\"http://publicobject.com/helloworld.txt\
39:headers
Http2ExchangeCodec
37:newStream
RetryAndFollowUpInterceptor
42:getSink()
7:initExchange
12:connectTunnel
24:awaitTaskToRun
46:writeData
38:newStream
RealConnection
33:proceed
二、ConnectInterceptor拦截器(初始化网络连接器)与 CallServerInterceptor拦截器(网络发送数据与读取数据)分析
0 条评论
回复 删除
下一页