OkHttp网络框架设计

OSI七层模型介绍,TCP/IP模型介绍,HTTP协议格式介绍

OSI七层模型

应用层------可见的终端(浏览器)

表示层------计算机识别的信息转变人可以识别的信息

回话层------传输端口和接受端口的建立回话

传输层------传输数据的协议与端口

网络层------IP地址

数据链路层------交换机传输

物理层------具体物理设备

TCP/IP模型 

应用层----http https REST REMT

传输层----Socket

应用层

主机至网络层

HTTP GET Request

发起请求:1.请求头之请求行 2.    请求头之请求属性集

HTTP POST Request

发起请求:1.请求头之请求行  2. 请求头之请求属性集  3.请求体长度 4.请求的类型

OKHttp主线流程的源码解读

OKHttp的使用:

OKHttpClient------Request------newCall 执行RealCall.enqueue(){不能重复执行}------

Dispatcher.enqueue(AsyncCall:if先加入运行队列,执行异步任务 else 直接加入等待队列)------AsyncCall.excute()区分责任划分判断是用户导致还是OKHttp导致的,责任链模式,多个拦截器,返回response。

OKHttp源码解读之线程池详解

线程池的作用就是避免重复创建和销毁线程耗费内存

ThreadPoolExecutorexecutor=new ThreadPoolExecutor(0,Integer.MAX_VALUE,60, TimeUnit.MILLISECONDS,new LinkedBlockingDeque());

参数一:corePoolSize 核心线程数

参数二:maximumPoolSize 最大线程数

参数三/四:时间数值 keepAliveTime   单位unit 时分秒

                    正在执行的任务数量>corePoolSize---->参数三、四才会起作用

                    任务执行完毕后,闲置超过参数三、四设置的时间,才会回收线程,在这段时间以内就会复用线程。

参数五:workQueue队列 会把超出的任务加入队列,缓存起来

OkHttp里面的线程池:

public synchronized ExecutorServiceexecutorService() {

if (executorService ==null) {

executorService =new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

        new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));

  }

return executorService;

}

有源码可知:OkHttp里面的线程池采用的是缓存策略,

OkHttp里面线程池,采用的是缓存方案+线程工厂+非守护线程

将核心线程设为0,只要runnable>1,60秒之内就会复用线程,超过60秒回收线程。

OKHttp源码阅读之构建者模式/责任链模式

构建着模式:链式编程结构清晰(方法返回client本身),通过Builder来实现参数的复制

责任链模式:将不同的模块分块,集成共同的接口,设置一个manager也集成共同的接口,将不同的模块添加到集合中,通过重写共同接口的方法,达到在集合中不断执行不同模块的功能,如果不符合条件就停止执行。

OKHttp 手写实现之整体框架搭建

根据OKHttp的源码创建自己的OkHttpClient2  Request2 Call2  CallBack2.....

public void uesMyOkHttp(View view) {

    OkHttpClient2 okHttpClient2 =new OkHttpClient2.Builder().build();

    Request2 request2 =new Request2.Builder().url("https://www.baidu.com").build();

    Call2 call = okHttpClient2.newCall(request2);

    call.enqueue(new CallBack2() {

    @Override

        public void onFailure(Call2 call, IOException e) {

    Log.e("eeeeeee",e.getMessage());

        }

@Override

        public void onResponse(Call2 call, Response2 response)throws IOException {

Log.e("eeeeeee",response.getBody());

        }

});

}

OkHttpClient2  Request2一样,都是采用创建者模式,链式编程可以传入自定义的参数、

public class OkHttpClient2 {

private Dispacher2dispacher2;

    private boolean isCancle;

    private Stringurl;

    private int recount;

    public int getRecount() {

return recount;

    }

public OkHttpClient2() {

this(new Builder());

    }

public OkHttpClient2(Builder builder) {

this.dispacher2 = builder.dispacher2;

        this.isCancle = builder.isCancle;

        this.url = builder.url;

        this.recount=builder.recount;

    }

public boolean getCanle() {

return isCancle;

    }

public static final class Builder {

private Stringurl;

        private Dispacher2dispacher2;

        private boolean isCancle;

        int recount =3;//默认重试3次

        public Builder() {

dispacher2 =new Dispacher2();

        }

public OkHttpClient2build() {

return new OkHttpClient2(this);

        }

public BuildersetCount(int recount) {

this.recount = recount;

return this;

        }

public Buildercancle() {

isCancle =true;

return this;

        }

public Builderdispacher(Dispacher2 dispacher2) {

this.dispacher2 = dispacher2;

return this;

        }

public Builderurl(String url) {

this.url = url;

return this;

        }

}

public Call2newCall(Request2 request2) {

return new RealCall2(request2, this);

    }

public Dispacher2dispacher() {

return dispacher2;

    }

}


public class Request2 {

public static final StringGET ="GET";

    public static final StringPOST ="POST";

    private Stringurl;

    public StringgetUrl() {

return url;

    }

public StringgetRequestMethod() {

return requestMethod;

    }

public MapgetmHeadList() {

return mHeadList;

    }

private StringrequestMethod =GET;

    private MapmHeadList =new HashMap<>();

    public Request2() {

this(new Builder());

    }

public Request2(Builder builder) {

this.url = builder.url;

        this.requestMethod = builder.requestMethod;

        this.mHeadList = builder.mHeadList;

    }

public static final class Builder {

private Stringurl;

        private StringrequestMethod =GET;

        private MapmHeadList =new HashMap<>();

        public Request2build() {

return new Request2(this);

        }

public Builderget() {

requestMethod =GET;

return this;

        }

public Builderpost() {

requestMethod =POST;

return this;

        }

public BuilderaddHead(String key, String value) {

mHeadList.put(key, value);

return this;

        }

public Builderurl(String url) {

this.url = url;

return this;

        }

}

}

定义一个接口Call2

public interface Call2 {

void enqueue(CallBack2 responseCallback);

}

定义一个RealCall实现Call2

public class RealCall2implements Call2 {

private boolean excuted;

    private Request2request2;

    private OkHttpClient2okHttpClient2;

    public boolean isExcuted() {

return excuted;

    }

public Request2getRequest2() {

return request2;

    }

public OkHttpClient2getOkHttpClient2() {

return okHttpClient2;

    }

public RealCall2(Request2 request2, OkHttpClient2 okHttpClient2) {

this.request2 = request2;

        this.okHttpClient2 = okHttpClient2;

    }

@Override

    public void enqueue(CallBack2 responseCallback) {

synchronized (this) {

if (excuted) {

excuted =true;

                throw new IllegalArgumentException("Already Executed");

            }

}

okHttpClient2.dispacher().enqueue(new AsyncCall2(responseCallback));

    }

public final class AsyncCall2implements Runnable {

private CallBack2callBack2;

        public Request2getRequest2() {

return RealCall2.this.request2;

        }

public AsyncCall2(CallBack2 callBack2) {

this.callBack2 = callBack2;

        }

@Override

        public void run() {

boolean signalledCallback =false;

            try {

Response2 response = getResponseWithInterceptorChain();

                if (okHttpClient2.getCanle()) {

signalledCallback =true;

                    callBack2.onFailure(RealCall2.this, new IOException("用户取消了 请求"));

                }else {

signalledCallback =true;

                    callBack2.onResponse(RealCall2.this, response);

                }

}catch (IOException e) {

//责任的划分

                if (signalledCallback) {//用户的操作

                    System.out.println("用户再使用过程中  出错了");

                }else {

callBack2.onFailure(RealCall2.this, new IOException("OKHttp getResponseWithInterceptorChain错误 e:" + e.toString()));

                }

}finally {//回收

                okHttpClient2.dispacher().finished(this);

            }

}

private Response2getResponseWithInterceptorChain()throws IOException {

Response2 response2 =new Response2();

            response2.setBody("流程走通");

            return response2;

        }

}

}

通过构造参数将前面的client和request传到RealCall里面 

重写enqueue方法,执行dispacher里面的enqueue方法

@Override

public void enqueue(CallBack2 responseCallback) {

synchronized (this) {

if (excuted) {

excuted =true;

            throw new IllegalArgumentException("Already Executed");

        }

}

okHttpClient2.dispacher().enqueue(new AsyncCall2(responseCallback));

}

创建Dipacher2 在enqueue方法里面判断是将任务添加到执行队列还是等待队列,添加到执行队列后利用线程池执行任务。    

通过finally {//回收

    okHttpClient2.dispacher().finished(this);

}

将等待队列的任务便利执行完毕。,还将run方法里面责任进行划分,明确是OK HTTP本身的责任还是使用者的责任,callBack2执行callback,将执行情况返回给页面,

Response2 response = getResponseWithInterceptorChain();通过责任链模式将response返回,详细情况在下面手写socket

public class Dispacher2 {

private int maxRequests =64;//同时访问任务,最大数量是64

    private int maxRequestsPerHost =5;//同时访问同一个服务器域名,最大限制

    private DequerunningAsyncCalls =new ArrayDeque<>();

    private DequereadyAsyncCalls =new ArrayDeque<>();

    public void enqueue(RealCall2.AsyncCall2 call) {

if (runningAsyncCalls.size()

runningAsyncCalls.add(call);//加入运行队列

            executorService().execute(call);//然后再执行

        }else {

readyAsyncCalls.add(call);//加入等待队列

        }

}

private ExecutorexecutorService() {

ExecutorService executorService =new ThreadPoolExecutor(0, 64, 60l, TimeUnit.MILLISECONDS, new SynchronousQueue(), new ThreadFactory() {

@Override

            public ThreadnewThread(Runnable r) {

Thread thread =new Thread(r);

                thread.setName("自定义的线程。。。");

                thread.setDaemon(false);

                return thread;

            }

});

        return executorService;

    }

/**

* 判断AsyncCall2中的Host,在运行的队列中,计数,然后返回

*/

    private int runningCallsForHost(RealCall2.AsyncCall2 call) {

int count =0;

        if (runningAsyncCalls.isEmpty()) {

return 0;

        }

SocketRequestSever src =new SocketRequestSever();

        //遍历运行队伍里面的所有人物,取出任务host==call.host +1

        for (RealCall2.AsyncCall2 runningAsyncCall :runningAsyncCalls) {

if (src.getHost(runningAsyncCall.getRequest2()).equals(call.getRequest2())) {

count++;

            }

}

return count;

    }

public void finished(RealCall2.AsyncCall2 call2) {

//当前运行队列

        runningAsyncCalls.remove(call2);

        //等待队列为空就返回

        if (readyAsyncCalls.isEmpty()) {

return;

        }

//把等待队列任务移动到运行队列

        for (RealCall2.AsyncCall2 readyAsyncCall :readyAsyncCalls) {

readyAsyncCalls.remove(readyAsyncCall);//杀出等待队列的任务

            runningAsyncCalls.add(readyAsyncCall);

            executorService().execute(readyAsyncCall);

        }

}

}

创建CallBack2和AsyncCall2

public interface CallBack2 {

    void onFailure(Call2 call, IOException e);

    void onResponse(Call2 call, Response2 response)throws IOException;

}

public final class AsyncCall2implements Runnable {

private CallBack2callBack2;

        public Request2getRequest2() {

return RealCall2.this.request2;

        }

public AsyncCall2(CallBack2 callBack2) {

this.callBack2 = callBack2;

        }

@Override

        public void run() {

boolean signalledCallback =false;

            try {

Response2 response = getResponseWithInterceptorChain();

                if (okHttpClient2.getCanle()) {

signalledCallback =true;

                    callBack2.onFailure(RealCall2.this, new IOException("用户取消了 请求"));

                }else {

signalledCallback =true;

                    callBack2.onResponse(RealCall2.this, response);

                }

}catch (IOException e) {

//责任的划分

                if (signalledCallback) {//用户的操作

                    System.out.println("用户再使用过程中  出错了");

                }else {

callBack2.onFailure(RealCall2.this, new IOException("OKHttp getResponseWithInterceptorChain错误 e:" + e.toString()));

                }

}finally {//回收

                okHttpClient2.dispacher().finished(this);

            }

}

private Response2getResponseWithInterceptorChain()throws IOException {

Response2 response2 =new Response2();

            response2.setBody("流程走通");

            return response2;

        }

}
自定义拦截器

首先创建Interceptor2接口

public interface Interceptor2 {

Response2doNext(Chain2 chain2)throws IOException;

}

创建一个充实拦截器ReRequestInterceptor 

public class ReRequestInterceptor implements Interceptor2 {

@Override

    public Response2doNext(Chain2 chain2)throws IOException {

ChainManager chainManager = (ChainManager) chain2;

        RealCall2 realCall2 = chainManager.getCall2();

        OkHttpClient2 okHttpClient2 = realCall2.getOkHttpClient2();

        IOException ioException =null;

        if (okHttpClient2.getRecount() !=0) {

for (int i =0; i < okHttpClient2.getRecount(); i++) {

try {

Response2 response2 = chain2.getResponse(chainManager.getRequest());

                    return response2;

                }catch (IOException e) {

ioException = e;

                }

}

}

throw ioException;

    }

}

创建Chain2接口

public interface Chain2 {

Request2getRequest();

    Response2getResponse(Request2 request2)throws IOException;

}


创建ChainManager,将拦截器存放到集合中,循环便利

public class ChainManager implements Chain2 {

private final Listinterceptors;

    private int index;

    private final Request2request2;

    private final RealCall2call2;

    public  ListgetInterceptors() {

return interceptors;

    }

public int getIndex() {

return index;

    }

public  RealCall2getCall2() {

return call2;

    }

public ChainManager(List interceptors, int index, Request2 request2, RealCall2 call2) {

this.interceptors = interceptors;

        this.index = index;

        this.request2 = request2;

        this.call2 = call2;

    }

@Override

    public Request2getRequest() {

return request2;

    }

@Override

    public Response2getResponse(Request2 request2)throws IOException {

if(index>interceptors.size())throw new AssertionError();

        if(interceptors.isEmpty())throw new IOException("interceptor is empty");

        ChainManager chainManager=new ChainManager(interceptors,index++,request2,call2);

        Interceptor2 interceptor=interceptors.get(index);

        Response2 response2=interceptor.doNext(chainManager);

        return response2;

    }

}


OKHttp 手写实现之socket请求与响应

创建SocketRequestServer

public class SocketRequestServer {

    private final String K = " ";

    private final String VIERSION = "HTTP/1.1";

    private final String GRGN = "\r\n";

    /**

    * todo 通过Request对象,寻找到域名HOST

    * @param request2

    * @return

    */

    public String getHost(Request2 request2) {

        try {

            // http://restapi.amap.com/v3/weather/weatherInfo?city=110101&key=13cb58f5884f9749287abbead9c658f2

            URL url = new URL(request2.getUrl());

            return url.getHost(); // restapi.amap.com

        } catch (MalformedURLException e) {

            e.printStackTrace();

        }

        return null;

    }

    /**

    * todo 端口

    * @param request2

    * @return

    */

    public int getPort(Request2 request2) {

        try {

            URL url = new URL(request2.getUrl());

            int port = url.getPort();

            return port == -1 ? url.getDefaultPort() : port;

        } catch (MalformedURLException e) {

            e.printStackTrace();

        }

        return -1;

    }

    /**

    * todo 获取请求头的所有信息

    * @param request2

    * @return

    */

    public String getRequestHeaderAll(Request2 request2) {

        // 得到请求方式

        URL url = null;

        try {

            url = new URL(request2.getUrl());

        } catch (MalformedURLException e) {

            e.printStackTrace();

        }

        String file = url.getFile();

        // TODO 拼接 请求头 的 请求行  GET /v3/weather/weatherInfo?city=110101&key=13cb58f5884f9749287abbead9c658f2 HTTP/1.1\r\n

        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append(request2.getRequestMethod()) // GET or POST

        .append(K)

        .append(file)

        .append(K)

        .append(VIERSION)

        .append(GRGN);

        // TODO 获取请求集 进行拼接

        /**

        * Content-Length: 48\r\n

        * Host: restapi.amap.com\r\n

        * Content-Type: application/x-www-form-urlencoded\r\n

        */

        if (!request2.getmHeaderList().isEmpty()) {

            Map<String,String> mapList = request2.getmHeaderList();

            for (Map.Entry<String, String> entry: mapList.entrySet()) {

                stringBuffer.append(entry.getKey())

                        .append(":").append(K)

                        .append(entry.getValue())

                        .append(GRGN);

            }

            // 拼接空行,代表下面的POST,请求体了

            stringBuffer.append(GRGN);

        }

        // TODO POST请求才有 请求体的拼接

        if ("POST".equalsIgnoreCase(request2.getRequestMethod())) {

            stringBuffer.append(request2.getRequestBody2().getBody()).append(GRGN);

        }

        return stringBuffer.toString();

    }

}


在getResponseWithInterceptorChain()里面添加

private Response2 getResponseWithInterceptorChain() throws IOException {

//            Response2 response2 = new Response2();

//            response2.setBody("流程走通....");

//            return response2;

            List<Interceptor2> interceptor2List = new ArrayList<>();

            interceptor2List.add(new ReRequestInterceptor()); // 重试拦截器

            interceptor2List.add(new RequestHeaderInterceptor()); // 请求头拦截器

            interceptor2List.add(new ConnectionServerInterceptor()); // 连接服务器的拦截器

            ChainManager chainManager = new ChainManager(interceptor2List, 0, request2, RealCall2.this);

            return chainManager.getResponse(request2); // 最终返回的Response

        }

    }

url 统一资源定位符

url.getHost()  域名

url.getPort()  端口

url.getFile()  传输文件

url.getProtocol()  协议

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容