洞察探索open banking如何通过小程序容器技术助力金融企业实现数据安全和数字化转型
605
2022-10-27
模拟OkHttp,手写简易版网络访问框架
开篇废话
趁着周末两天的时间,跟着大神的脚步,把我们经常使用的网络框架OkHttp的源码好好跟了一下,初次观看,确实非常容易钻进去,搞得云里雾里,在大神的指导下,才勉强把整个逻辑走通。写这篇文章,也是希望自己脑袋里面,能对这个网络框架有一个整体的认识,了解它整体设计思想。
大概了解后,还是需要自己亲自动手,来手写当中的一些细节,加深自己理解,所以,接下来,我会给出OkHttp中设计的主线,以及模拟OkHttp,手写一个属于我们自己的网络框架。
废话就到此为止了,开始这次的学习之旅吧。。。
技术详情
1. OkHttp 的主线调用
关于OkHttp的使用,我这里就不说了,不清楚的可以,在简书里面搜索一下,应该有非常多文章来说明,我这里就大概说一下调用的主线流程。
OkHttp中-的整体调用逻辑,可以查看下面这张图,可以说非常清晰了,细节地方,自己可以去查看源码了:
对于当中具体调用细节,我这里就不再讲述了,可以根据手写的简易OkHttp框架来对它们有一个整体的认识。
2. 模拟OkHttp,手写简易Http框架
对OkHttp的设计思路有一个整体的认识后,自己手写一个简易版的Http框架,加深一下对OkHttp源码的认识。手写Http框架,当中能够学到以下知识点:
1.对于http协议能够有熟悉的认识 2.线程池的项目实践 3.建造者模式的项目实践 4.socket层的字节流处理 5.责任链模式的项目实践,熟悉OkHttp中的责任链模式的-
首先,根据使用者习惯,完成HttpClient的功能(建造者模式):
使用者能够通过设置失败重试次数,自定义-构造一个httpClient对象
得到HttpClient对象后,就能拿到Call对象了,以下是Call里面的实现:
public class Call { private HttpClient httpClient; private Request request; public Request getRequest() { return request; } public HttpClient getHttpClient() { return httpClient; } //TODO 是否被执行过 boolean executed; //TODO 是否被取消了 boolean canceled; public boolean isCanceled() { return canceled; } public Call(HttpClient httpClient, Request request){ this.httpClient = httpClient; this.request = request; } /** * 获取返回 * @return * @throws IOException */ Response getResponse() throws IOException{ ArrayList
Call类中的AsyncCall线程,是请求真正开始的地方,使用者调用enqueue的时候,只是把这个AsyncCall线程添加到调度器Dispather的线程池,其中,Dispacher中的实现如下:
调度器中只是负责把添加进来的请求进行按序执行管理,真正执行,还是在AsyncCall线程中run方法,其中的责任链式的-,也在这里面进行添加,执行。 我这里自己手写的-,没有像OkHttp那么全而细,知道它的设计思想后,自己只是手动实现一个简单的责任链-,其中包括
1.重试-2.Http头-3.选择有效socket连接的-4.socket通信-
这个顺序是不能随意调换的,就跟工厂里面的流水线一样,一步一步往下走的。 首先,实现的是重试-
public class RetryInterceptor implements Interceptor { @Override public Response intercept(InterceptorChain interceptorChain) throws IOException { Log.e("interceprot", "重试-...."); Call call = interceptorChain.call; IOException ioException = null; for(int i = 0 ; i < call.getHttpClient().getRetryTimes(); i ++){ if(call.isCanceled()){ throw new IOException("this task had canceled"); } try { Response response = interceptorChain.proceed(); return response; }catch (IOException e){ ioException = e; } } throw ioException; }}
然后是Http头处理的-
public class HeadersInterceptor implements Interceptor { @Override public Response intercept(InterceptorChain interceptorChain) throws IOException { Log.e("interceprot","Http头-...."); Request request = interceptorChain.call.getRequest(); Map
接着是选择可用socket连接的-
public class ConnectionInterceptor implements Interceptor { @Override public Response intercept(InterceptorChain interceptorChain) throws IOException { Log.e("interceptor", "获取连接-"); Request request = interceptorChain.call.getRequest(); HttpClient httpClient = interceptorChain.call.getHttpClient(); HttpUrl httpUrl = request.getHttpUrl(); HttpConnection httpConnection = httpClient.getConnectionPool().getHttpConnection(httpUrl.getHost(),httpUrl.getPort()); if(null == httpConnection){ httpConnection = new HttpConnection(); }else{ Log.e("interceptor", "从连接池中获得连接"); } httpConnection.setRequest(request); try { Response response = interceptorChain.proceed(httpConnection); if (response.isKeepAlive()){ httpClient.getConnectionPool().putHttpConnection(httpConnection); }else{ httpConnection.close(); } return response; }catch (IOException e){ httpConnection.close(); throw e; } }}
把请求的配置信息都配置好后,最后,交给socket去通信,去解析,就是socket通信-了:
public class CallServiceInterceptor implements Interceptor { @Override public Response intercept(InterceptorChain interceptorChain) throws IOException { Log.e("interceptor", "通信-"); HttpConnection httpConnection = interceptorChain.httpConnection; HttpCodec httpCodec = new HttpCodec(); InputStream inputStream = httpConnection.call(httpCodec); //获取服务器返回的响应行 HTTP/1.1 200 OK\r\n String statusLine = httpCodec.readLine(inputStream); //获取服务器返回的响应头 Map
经过以上四个-后,使用者就能够正常使用http或者https的请求了。这里面还有一些额外处理的类,我这里就没有给出来了,具体的可以去我的github上查看项目源码,注释写了蛮多,应该很好理解。
关于此项目的源代码,在文章最后,会提供github地址,欢迎star
干货总结
阅读框架源码,说真的,确实是一件非常蛋疼的事,但是为了提升自己,却不得不去啃这个硬骨头,学习他人优秀的设计思想为己所用。只有积累的足够多方法之后,我们才能真正得去创造。
对于我们项目中框架的使用,会引入很多不一样的框架,比如retrofit(okhttp),glide,greenDao数据库框架,arouter路由框架,rxjava,butterknife,以及一些其他的第三方自定义控件等,就会不知不觉是我们的项目越发的庞大,而且比较难以维护,所以,建议我们自己项目,能够尽量自己手写相关的框架,而不要直接引用别人的(我个人的愿景,不喜勿喷)。
希望通过此文章以及源码,能够学习到以下知识点,也不枉我码了那么多字:
1.对于http协议能够有熟悉的认识 2.线程池的项目实践 3.建造者模式的项目实践 4.socket层的字节流处理 5.责任链模式的项目实践,熟悉OkHttp中的责任链模式的-
接下来的日子,希望能够对数据库框架,路由框架,图片加载框架,换肤框架,热更新框架等框架,进行熟悉,然后给出自己手写的简易版本,提升自身对于这些框架的认识。
以下是我的博客地址:
项目的简书地址
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~