其实你可以读懂OKHttp3的源码

来源:互联网 发布:淘宝运营教材 编辑:程序博客网 时间:2024/05/16 13:06

因为公司的项目中使用了的Retrofit2+OK3,所以有时间闲下来还是有必要研究一下它的源码,本来就抱着试试看的心态,项目上线了,休息休息也是可以的,呵呵。所以就走马观花的去读了一遍,写下自己的分享,作为一个新人,在没有提前看别人的分析的情况下,我想我是看懂了一点点,大家不要见笑。基于OK3的源码啊。。

先来看个请求吧,普通的GET请求,服务器也是我自己搭建的(thinkPHP3.3环境,不要问我为什么会PHP,人都是鼻出来的!),来看代码:

Request.Builder builder = new Request.Builder().url(Api.GET_URL);final Request request = builder.build();OkHttpClient mOkHttpClient = new OkHttpClient() ;        Call mCall = mOkHttpClient.newCall(request);mCall.enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                Log.d(TAG , "onFailure : " + call );                Log.d(TAG , "onFailure exception : " + e) ;            }            @Override            public void onResponse(Call call, Response response) throws IOException {                Log.d(TAG , Thread.currentThread().getName() + "onResponse : " + call);                Log.d(TAG, Thread.currentThread().getName() + " the response is " + response.body().string()) ;            }        });

先看Request.Builder吧,这个我先说一下吧,Request英文名对应请求,那么它肯定就是ok3封装的请求数据,Builder见得多了,装13一点就是Builder模式,写过android的对话框的,AlertDialog.Builder跟它一个样,顺便截个图,看看Request.Builder中到底有什么:
这里写图片描述
是的,它有HttpUrl,method,Header.Builder,RequestBody,tag。我们就简单理解一下吧,分别就是请求的Url,method,header 和 请求的body吧,这个先不看,简单了解一下,我想想也是,哈哈。

再来看这句代码吧:

OkHttpClient mOkHttpClient = new OkHttpClient() ;        Call mCall = mOkHttpClient.newCall(request);

我们来看看newCall是干嘛用的:
这里写图片描述
它返回了一个newCall的东西,不管了,先提着裤子进去看看吧:
这里写图片描述
看不懂啊,先放着,接着看下面的代码:

mCall.enqueue(new callback);

此时的mCall就是我们已知的realCall,看看它的enqueue方法是做啥的:
这里写图片描述

信息量比较大,还是挑重点的吧,调用的了

 client.dispatcher().enqueue(new AsyncCall(responseCallback));

这个client就是我们的OkHttpClient,那么这个dispatcher是什么呢?进去看看吧:
这里写图片描述
英文解释为异步的请求策略,看到下面的ExecutorService就是用线程池了,现在也不管最大并发数是多少了,自己进来看看就知道了。这个dispatcher应该就是OK3分发异步请求核心了,我们去看看它的enqueue方法了:
这里写图片描述
信息量也是比较大,我也就不展开扯了,判断正在执行的call数量和访问同一主机的数量,这些都不重要,重要的是看到了executorService().execute(call);多线程中学到了executorService.executte方法中,一定传入的是个Runnable对象,那么好吧,我们来看看这个AsyncCall对象是什么玩意吧:
这里写图片描述
看到了吧,的确是实现了Runnable接口的货,那个NamedRunnable是实现了Runnable接口,用意是要在Runnable在run时有个好用的名字,官方说为了避免每次设置名字而创建的:
这里写图片描述

看完了这,那就看看AsyncCall中的execute方法吧:
这里写图片描述

到现在为止,我们找到了在开始请求时,设置的Callback,在这里已经看到原型了,非常开心,非常高兴了,感觉马上就需要完成了啊。
我们的Response来自getResponseWithInterceptorChain()方法,进去看看了,看完了马上就可以睡觉了:
这里写图片描述

来看看这个图,为了这个方法我硬是傻了很长一段时间,设计了一个拦截器容器,装入了client.Interceptor,失败和重定向的Interceptor,请求头的Interceptor,还有缓存的Interceptor,连接用的Interceptor,还有netWork的Interceptor,最后一个连接服务器的Interceptor。
然后让我们的RealInterceptorChain进行process后获得Response,注意RealInterceptorChain中第四个参数是0,这个很有用。

现在进入RealInterceptorChain看看process方法:
这里写图片描述

前面一段是interceptor是合法性检测,不是我们的重点,重点是这个:

    // 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);

最后直接interceptor.intercept(next)返回了Response,那好,我们来看看这个Interceptor接口是什么吧:
这里写图片描述
可以看到,Interceptor.intercept中传入的是一个Chain接口,重点还是看段代码,我又贴了一遍:

RealInterceptorChain next = new RealInterceptorChain(interceptors,     streamAllocation,     httpCodec,     connection,     **index + 1**,     request);    Interceptor interceptor = interceptors.get(index);    Response response = interceptor.intercept(next);

光说图不是很明白,来张灵魂画工,估计能明白一点吧:
这里写图片描述
好了,看这张图我想你能明白我在说什么了,就是通过Chain的方式,将我们的Interceptor串联起来执行的,而且这个Chain名词也很形象,本身含义是链条的意思,的确啊,将所有的Interceptor连接起来,不就是链条么?这种模式我们称之为责任链模式,可能架构多了,很多东西都一样了吧,在web三个框架中Struct中,拦截器也是这么写的,使用责任链模式,非常的优雅和有效,值得我们学习啊。

至于到最后一个Interceptor.Intercept总该返回我们需要的Response吧,来看看最后一个Interceptor是什么了吧,不要忘记这张图啊:
这里写图片描述
最后一个是什么呢?是CallServerInterceptor,不说了,先进去看看intercept方法吧:

@Override public Response intercept(Chain chain) throws IOException {    ...    Response response = responseBuilder        .request(request)        .handshake(streamAllocation.connection().handshake())        .sentRequestAtMillis(sentRequestMillis)        .receivedResponseAtMillis(System.currentTimeMillis())        .build();    int code = response.code();    if (forWebSocket && code == 101) {      response = response.newBuilder()          .body(Util.EMPTY_RESPONSE)          .build();    } else {      response = response.newBuilder()          .body(httpCodec.openResponseBody(response))          .build();    }    ....    return response;  }

代码都省略了啊,可以看出,最后一个使我们真正请求的Interceptor,并在这里完成了Response的组装,最后进行了返回,这个类里面涉及了很多http的知识,三次握手,返回码的知识等等,有时间再学习学习吧,这次写的还是有点多了。

通过简单的学习,我们了解一次OKHttp的请求,还是蛮复杂的,不能不说这样的设计真的需要水平,膜拜一下啊,当然了,很多地方也可能有错误或者分析不到位,希望大家指出啊,我也是只是写下自己的想法,大家共同进步吧。

1 0