OKHttp源码解析(三)

来源:互联网 发布:淘宝p图用什么软件 编辑:程序博客网 时间:2024/05/29 16:20
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">readResponse</span>() <span class="hljs-keyword">throws</span> IOException {        <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.userResponse == <span class="hljs-keyword">null</span>) {            <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.networkRequest == <span class="hljs-keyword">null</span> && <span class="hljs-keyword">this</span>.cacheResponse == <span class="hljs-keyword">null</span>) {                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"call sendRequest() first!"</span>);            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.networkRequest != <span class="hljs-keyword">null</span>) {                Response networkResponse;                <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.forWebSocket) {                    <span class="hljs-keyword">this</span>.transport.writeRequestHeaders(<span class="hljs-keyword">this</span>.networkRequest);                    networkResponse = <span class="hljs-keyword">this</span>.readNetworkResponse();                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!<span class="hljs-keyword">this</span>.callerWritesRequestBody) {                <span class="hljs-comment">//利用拦截器方式去做答复处理</span>                    networkResponse = (<span class="hljs-keyword">new</span> HttpEngine.NetworkInterceptorChain(<span class="hljs-number">0</span>, <span class="hljs-keyword">this</span>.networkRequest)).proceed(<span class="hljs-keyword">this</span>.networkRequest);                } <span class="hljs-keyword">else</span> {                    <span class="hljs-comment">//这个else分句可以不看</span>                }                <span class="hljs-keyword">this</span>.receiveHeaders(networkResponse.headers());                <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.cacheResponse != <span class="hljs-keyword">null</span>) {                    <span class="hljs-keyword">if</span>(validate(<span class="hljs-keyword">this</span>.cacheResponse, networkResponse)) {                        <span class="hljs-keyword">this</span>.userResponse = <span class="hljs-keyword">this</span>.cacheResponse.newBuilder().request(<span class="hljs-keyword">this</span>.userRequest).priorResponse(stripBody(<span class="hljs-keyword">this</span>.priorResponse)).headers(combine(<span class="hljs-keyword">this</span>.cacheResponse.headers(), networkResponse.headers())).cacheResponse(stripBody(<span class="hljs-keyword">this</span>.cacheResponse)).networkResponse(stripBody(networkResponse)).build();                        networkResponse.body().close();                        <span class="hljs-keyword">this</span>.releaseConnection();                        InternalCache responseCache1 = Internal.instance.internalCache(<span class="hljs-keyword">this</span>.client);                        responseCache1.trackConditionalCacheHit();                        responseCache1.update(<span class="hljs-keyword">this</span>.cacheResponse, stripBody(<span class="hljs-keyword">this</span>.userResponse));                        <span class="hljs-keyword">this</span>.userResponse = <span class="hljs-keyword">this</span>.unzip(<span class="hljs-keyword">this</span>.userResponse);                        <span class="hljs-keyword">return</span>;                    }                    Util.closeQuietly(<span class="hljs-keyword">this</span>.cacheResponse.body());                }                <span class="hljs-keyword">this</span>.userResponse = networkResponse.newBuilder().request(<span class="hljs-keyword">this</span>.userRequest).priorResponse(stripBody(<span class="hljs-keyword">this</span>.priorResponse)).cacheResponse(stripBody(<span class="hljs-keyword">this</span>.cacheResponse)).networkResponse(stripBody(networkResponse)).build();                <span class="hljs-keyword">if</span>(hasBody(<span class="hljs-keyword">this</span>.userResponse)) {                    <span class="hljs-keyword">this</span>.maybeCache();                    <span class="hljs-keyword">this</span>.userResponse = <span class="hljs-keyword">this</span>.unzip(<span class="hljs-keyword">this</span>.cacheWritingResponse(<span class="hljs-keyword">this</span>.storeRequest, <span class="hljs-keyword">this</span>.userResponse));                }            }        }    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li></ul>

在上篇文章结尾OKHttp源码解析(二) 我们分析到这里第10行的callerWritesRequestBody会为空,所以我会直接进去这个判断,同样在OKHttp源码解析(一) 我们分析过发送请求时使用的拦截器模式,这里对答复的操作也用了同样的方式,不同于请求调用的是intercept,这里用的是proceed,我们就来看看这个方法做了什么

<code class="hljs avrasm has-numbering">public Response proceed(Request request) throws IOException {            ++this<span class="hljs-preprocessor">.calls</span><span class="hljs-comment">;</span>            if(this<span class="hljs-preprocessor">.index</span> > <span class="hljs-number">0</span>) {                Interceptor response = (Interceptor)HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.client</span><span class="hljs-preprocessor">.networkInterceptors</span>()<span class="hljs-preprocessor">.get</span>(this<span class="hljs-preprocessor">.index</span> - <span class="hljs-number">1</span>)<span class="hljs-comment">;</span>                Address code = this<span class="hljs-preprocessor">.connection</span>()<span class="hljs-preprocessor">.getRoute</span>()<span class="hljs-preprocessor">.getAddress</span>()<span class="hljs-comment">;</span>                if(!request<span class="hljs-preprocessor">.url</span>()<span class="hljs-preprocessor">.getHost</span>()<span class="hljs-preprocessor">.equals</span>(code<span class="hljs-preprocessor">.getUriHost</span>()) || Util<span class="hljs-preprocessor">.getEffectivePort</span>(request<span class="hljs-preprocessor">.url</span>()) != code<span class="hljs-preprocessor">.getUriPort</span>()) {                    throw new IllegalStateException(<span class="hljs-string">"network interceptor "</span> + response + <span class="hljs-string">" must retain the same host and port"</span>)<span class="hljs-comment">;</span>                }                if(this<span class="hljs-preprocessor">.calls</span> > <span class="hljs-number">1</span>) {                    throw new IllegalStateException(<span class="hljs-string">"network interceptor "</span> + response + <span class="hljs-string">" must call proceed() exactly once"</span>)<span class="hljs-comment">;</span>                }            }            if(this<span class="hljs-preprocessor">.index</span> < HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.client</span><span class="hljs-preprocessor">.networkInterceptors</span>()<span class="hljs-preprocessor">.size</span>()) {            //根据拦截器的数目去相应取出拦截器并执行intercept里面用户自定义的处理方式                HttpEngine<span class="hljs-preprocessor">.NetworkInterceptorChain</span> var7 = HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.new</span> NetworkInterceptorChain(this<span class="hljs-preprocessor">.index</span> + <span class="hljs-number">1</span>, request)<span class="hljs-comment">;</span>                Interceptor var10 = (Interceptor)HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.client</span><span class="hljs-preprocessor">.networkInterceptors</span>()<span class="hljs-preprocessor">.get</span>(this<span class="hljs-preprocessor">.index</span>)<span class="hljs-comment">;</span>                Response interceptedResponse = var10<span class="hljs-preprocessor">.intercept</span>(var7)<span class="hljs-comment">;</span>                if(var7<span class="hljs-preprocessor">.calls</span> != <span class="hljs-number">1</span>) {                    throw new IllegalStateException(<span class="hljs-string">"network interceptor "</span> + var10 + <span class="hljs-string">" must call proceed() exactly once"</span>)<span class="hljs-comment">;</span>                } else {                    return interceptedResponse<span class="hljs-comment">;</span>                }            } else {            //写入请求头部                    HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.transport</span><span class="hljs-preprocessor">.writeRequestHeaders</span>(request)<span class="hljs-comment">;</span>                HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.networkRequest</span> = request<span class="hljs-comment">;</span>                if(HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.permitsRequestBody</span>() && request<span class="hljs-preprocessor">.body</span>() != null) {                //写入一些请求体                    Sink var5 = HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.transport</span><span class="hljs-preprocessor">.createRequestBody</span>(request, request<span class="hljs-preprocessor">.body</span>()<span class="hljs-preprocessor">.contentLength</span>())<span class="hljs-comment">;</span>                    BufferedSink var8 = Okio<span class="hljs-preprocessor">.buffer</span>(var5)<span class="hljs-comment">;</span>                    request<span class="hljs-preprocessor">.body</span>()<span class="hljs-preprocessor">.writeTo</span>(var8)<span class="hljs-comment">;</span>                    var8<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span>                }                //将之前写入的数据flush给socket并读取服务器答复                Response var6 = HttpEngine<span class="hljs-preprocessor">.this</span><span class="hljs-preprocessor">.readNetworkResponse</span>()<span class="hljs-comment">;</span>                int var9 = var6<span class="hljs-preprocessor">.code</span>()<span class="hljs-comment">;</span>                if((var9 == <span class="hljs-number">204</span> || var9 == <span class="hljs-number">205</span>) && var6<span class="hljs-preprocessor">.body</span>()<span class="hljs-preprocessor">.contentLength</span>() > <span class="hljs-number">0</span>L) {                    throw new ProtocolException(<span class="hljs-string">"HTTP "</span> + var9 + <span class="hljs-string">" had non-zero Content-Length: "</span> + var6<span class="hljs-preprocessor">.body</span>()<span class="hljs-preprocessor">.contentLength</span>())<span class="hljs-comment">;</span>                } else {                    return var6<span class="hljs-comment">;</span>                }            }        }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li></ul>

我们先来看看27行的头部写入是怎么一个写法

<code class="hljs avrasm has-numbering">public void writeRequestHeaders(Request request) throws IOException {        this<span class="hljs-preprocessor">.httpEngine</span><span class="hljs-preprocessor">.writingRequestHeaders</span>()<span class="hljs-comment">;</span>        //组装请求的信息,比如url,请求方式,请求协议        String requestLine = RequestLine<span class="hljs-preprocessor">.get</span>(request, this<span class="hljs-preprocessor">.httpEngine</span><span class="hljs-preprocessor">.getConnection</span>()<span class="hljs-preprocessor">.getRoute</span>()<span class="hljs-preprocessor">.getProxy</span>()<span class="hljs-preprocessor">.type</span>(), this<span class="hljs-preprocessor">.httpEngine</span><span class="hljs-preprocessor">.getConnection</span>()<span class="hljs-preprocessor">.getProtocol</span>())<span class="hljs-comment">;</span>        //将请求头和请求体写入socket        this<span class="hljs-preprocessor">.httpConnection</span><span class="hljs-preprocessor">.writeRequest</span>(request<span class="hljs-preprocessor">.headers</span>(), requestLine)<span class="hljs-comment">;</span>    }public void writeRequest(Headers headers, String requestLine) throws IOException {        if(this<span class="hljs-preprocessor">.state</span> != <span class="hljs-number">0</span>) {            throw new IllegalStateException(<span class="hljs-string">"state: "</span> + this<span class="hljs-preprocessor">.state</span>)<span class="hljs-comment">;</span>        } else {            this<span class="hljs-preprocessor">.sink</span><span class="hljs-preprocessor">.writeUtf</span>8(requestLine)<span class="hljs-preprocessor">.writeUtf</span>8(<span class="hljs-string">"\r\n"</span>)<span class="hljs-comment">;</span>            int i = <span class="hljs-number">0</span><span class="hljs-comment">;</span>            for(int size = headers<span class="hljs-preprocessor">.size</span>()<span class="hljs-comment">; i < size; ++i) {</span>                this<span class="hljs-preprocessor">.sink</span><span class="hljs-preprocessor">.writeUtf</span>8(headers<span class="hljs-preprocessor">.name</span>(i))<span class="hljs-preprocessor">.writeUtf</span>8(<span class="hljs-string">": "</span>)<span class="hljs-preprocessor">.writeUtf</span>8(headers<span class="hljs-preprocessor">.value</span>(i))<span class="hljs-preprocessor">.writeUtf</span>8(<span class="hljs-string">"\r\n"</span>)<span class="hljs-comment">;</span>            }            this<span class="hljs-preprocessor">.sink</span><span class="hljs-preprocessor">.writeUtf</span>8(<span class="hljs-string">"\r\n"</span>)<span class="hljs-comment">;</span>            this<span class="hljs-preprocessor">.state</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>        }    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul>

上面的sink就是socket的写入流,在上篇文章我们分析过怎么得到它的,将请求头部和请求体写入socket后,proceed的第37行就要进行flush操作了

<code class="hljs avrasm has-numbering">private Response readNetworkResponse() throws IOException {    //执行flush操作        this<span class="hljs-preprocessor">.transport</span><span class="hljs-preprocessor">.finishRequest</span>()<span class="hljs-comment">;</span>        //等待服务器相应并读取服务器返回信息组装成我们需要的response        Response networkResponse = this<span class="hljs-preprocessor">.transport</span><span class="hljs-preprocessor">.readResponseHeaders</span>()<span class="hljs-preprocessor">.request</span>(this<span class="hljs-preprocessor">.networkRequest</span>)<span class="hljs-preprocessor">.handshake</span>(this<span class="hljs-preprocessor">.connection</span><span class="hljs-preprocessor">.getHandshake</span>())<span class="hljs-preprocessor">.header</span>(OkHeaders<span class="hljs-preprocessor">.SENT</span>_MILLIS, Long<span class="hljs-preprocessor">.toString</span>(this<span class="hljs-preprocessor">.sentRequestMillis</span>))<span class="hljs-preprocessor">.header</span>(OkHeaders<span class="hljs-preprocessor">.RECEIVED</span>_MILLIS, Long<span class="hljs-preprocessor">.toString</span>(System<span class="hljs-preprocessor">.currentTimeMillis</span>()))<span class="hljs-preprocessor">.build</span>()<span class="hljs-comment">;</span>        if(!this<span class="hljs-preprocessor">.forWebSocket</span>) {        //组装response的body            networkResponse = networkResponse<span class="hljs-preprocessor">.newBuilder</span>()<span class="hljs-preprocessor">.body</span>(this<span class="hljs-preprocessor">.transport</span><span class="hljs-preprocessor">.openResponseBody</span>(networkResponse))<span class="hljs-preprocessor">.build</span>()<span class="hljs-comment">;</span>        }        Internal<span class="hljs-preprocessor">.instance</span><span class="hljs-preprocessor">.setProtocol</span>(this<span class="hljs-preprocessor">.connection</span>, networkResponse<span class="hljs-preprocessor">.protocol</span>())<span class="hljs-comment">;</span>        return networkResponse<span class="hljs-comment">;</span>    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

先简单看下第三行finishRequest调用的代码

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">finishRequest</span>() <span class="hljs-keyword">throws</span> IOException {        <span class="hljs-keyword">this</span>.httpConnection.flush();    }<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">flush</span>() <span class="hljs-keyword">throws</span> IOException {        <span class="hljs-keyword">this</span>.sink.flush();    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

再来看看第5行的组装步骤

<code class="hljs avrasm has-numbering">public Builder readResponseHeaders() throws IOException {        return this<span class="hljs-preprocessor">.httpConnection</span><span class="hljs-preprocessor">.readResponse</span>()<span class="hljs-comment">;</span>    }public Builder readResponse() throws IOException {        if(this<span class="hljs-preprocessor">.state</span> != <span class="hljs-number">1</span> && this<span class="hljs-preprocessor">.state</span> != <span class="hljs-number">3</span>) {            throw new IllegalStateException(<span class="hljs-string">"state: "</span> + this<span class="hljs-preprocessor">.state</span>)<span class="hljs-comment">;</span>        } else {            try {                StatusLine e<span class="hljs-comment">;</span>                Builder exception1<span class="hljs-comment">;</span>                do {                //从输入流里读出答复并组装成答复消息                    e = StatusLine<span class="hljs-preprocessor">.parse</span>(this<span class="hljs-preprocessor">.source</span><span class="hljs-preprocessor">.readUtf</span>8LineStrict())<span class="hljs-comment">;</span>                    exception1 = (new Builder())<span class="hljs-preprocessor">.protocol</span>(e<span class="hljs-preprocessor">.protocol</span>)<span class="hljs-preprocessor">.code</span>(e<span class="hljs-preprocessor">.code</span>)<span class="hljs-preprocessor">.message</span>(e<span class="hljs-preprocessor">.message</span>)<span class="hljs-comment">;</span>                    <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.squareup</span><span class="hljs-preprocessor">.okhttp</span><span class="hljs-preprocessor">.Headers</span><span class="hljs-preprocessor">.Builder</span> headersBuilder = new <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.squareup</span><span class="hljs-preprocessor">.okhttp</span><span class="hljs-preprocessor">.Headers</span><span class="hljs-preprocessor">.Builder</span>()<span class="hljs-comment">;</span>                    //答复头部的读取                    this<span class="hljs-preprocessor">.readHeaders</span>(headersBuilder)<span class="hljs-comment">;</span>                    headersBuilder<span class="hljs-preprocessor">.add</span>(OkHeaders<span class="hljs-preprocessor">.SELECTED</span>_PROTOCOL, e<span class="hljs-preprocessor">.protocol</span><span class="hljs-preprocessor">.toString</span>())<span class="hljs-comment">;</span>                    exception1<span class="hljs-preprocessor">.headers</span>(headersBuilder<span class="hljs-preprocessor">.build</span>())<span class="hljs-comment">;</span>                } while(e<span class="hljs-preprocessor">.code</span> == <span class="hljs-number">100</span>)<span class="hljs-comment">;</span>                this<span class="hljs-preprocessor">.state</span> = <span class="hljs-number">4</span><span class="hljs-comment">;</span>                return exception1<span class="hljs-comment">;</span>            } catch (EOFException var4) {                IOException exception = new IOException(<span class="hljs-string">"unexpected end of stream on "</span> + this<span class="hljs-preprocessor">.connection</span> + <span class="hljs-string">" (recycle count="</span> + Internal<span class="hljs-preprocessor">.instance</span><span class="hljs-preprocessor">.recycleCount</span>(this<span class="hljs-preprocessor">.connection</span>) + <span class="hljs-string">")"</span>)<span class="hljs-comment">;</span>                exception<span class="hljs-preprocessor">.initCause</span>(var4)<span class="hljs-comment">;</span>                throw exception<span class="hljs-comment">;</span>            }        }    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

上面的代码我们看到的是对答复头部的读取整理,而readNetworkResponse()第8行则是对服务器答复的body进行整理组装

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> ResponseBody <span class="hljs-title">openResponseBody</span>(Response response) <span class="hljs-keyword">throws</span> IOException {        Source source = <span class="hljs-keyword">this</span>.getTransferStream(response);        <span class="hljs-comment">//最终返回一个输入流</span>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RealResponseBody(response.headers(), Okio.buffer(source));    }    <span class="hljs-keyword">private</span> Source <span class="hljs-title">getTransferStream</span>(Response response) <span class="hljs-keyword">throws</span> IOException {        <span class="hljs-keyword">if</span>(!HttpEngine.hasBody(response)) {            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.httpConnection.newFixedLengthSource(<span class="hljs-number">0</span>L);        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-string">"chunked"</span>.equalsIgnoreCase(response.header(<span class="hljs-string">"Transfer-Encoding"</span>))) {            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.httpConnection.newChunkedSource(<span class="hljs-keyword">this</span>.httpEngine);        } <span class="hljs-keyword">else</span> {            <span class="hljs-keyword">long</span> contentLength = OkHeaders.contentLength(response);            <span class="hljs-keyword">return</span> contentLength != -<span class="hljs-number">1</span>L?<span class="hljs-keyword">this</span>.httpConnection.newFixedLengthSource(contentLength):<span class="hljs-keyword">this</span>.httpConnection.newUnknownLengthSource();        }    }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>

在经过这么层层代码的深入(好多代码,看得都乱了吧),我们最终得到了服务器返回的userResponse。。

最后的最后,我们要回到OKHttp源码解析(一) 最后一段代码getResponse的52行得到我们上面分析的userResponse,并关闭相应的连接池,关闭回收socket等”善后“处理。

三篇文章分析到现在,算是把整个OKHttp的流程分析了个大概,OkHttp还有其他的一些部分,比如handshake,连接池的管理等方面的内容,如果有人有发现这方面介绍的好文章可以留言推荐给我看看,大家共同学习,共同进步。

0 0
原创粉丝点击