6.1开源框架-okhttp网络框架-详解

okhttp网络框架

    1. OkHttp使用简介
    1. OkHttp源码剖析

1.OkHttp使用简介




    1. 创建客户端
      OkhttpClient client = new OkHttpClient();//作为单例,这样所有的请求可以公共response缓存和线程池
    1. 创建Request对象
      Request request = new Request.Builder().url("http://xxx").build();
      图上:封装了Http的一些请求信息
      Builder模式构建,builder模式会将它的显示和创建所分离
    1. 创建Call对象,call对象就是一个Http请求,execute开始执行
      okttp3.Response response = client.newCall(request).execute();
      //其中Call是连接request和Response的的桥梁
      Call对象既可以同步获取时间,也可以异步获取获取
     //同步获取方法   
    if(!response.isSuccessful())
        throw new IOException("Unexpected code "+response);
        
    Headers responseHeaders = response.headers()
    for(int i=0;i<responseHeaders.size();i++){
        System.out.println(responseHeaders.name(i)+": "+responseHeaders.value(i));
    }
    System.out.println(response.body().string());

同步获取数据它会阻塞当前线程去请求数据,返回response对象给线程.response也会包含状态码,响应头,响应body

    //异步获取方法:
    //前两步一样:
    client.newCall(request).enqueue(new Callback(){
        public void onFailure(Call call,IOException e){
            e.printStackTrace();
        }
        public void onResponse(Call call,okhttp3.Response response) throws IOExcepiton{
            if(!response.isSuccessful())
                throw new IOException("Unexpected code "+response);
            Headers responseHeaders = response.headers();
            for(int i=0;i<responseHeaders.size();i++){
                System.out.println(responseHeaders.name(i)+": "+responseHeaders.value(i));
            }
            System.out.println(response.body().string());
        }
    })

enqueue方法不会阻塞当前进程,会开启子线程,网络请求在子线程操作,当请求结束后,会回调成功、失败(在工作线程中执行)

2.OkHttp源码剖析

图:



7-1 okhttp网络框架面[00_06_58][20180721-155323-5].jpg
1. Application
2.Application INTERCEPTORS 包括↓request ↑response
OkHttp core

1.↓CACHE ↑CACHE 2.NETWORK INTERCEPTORS ↓request ↑response

    1. 创建客户端
      OkhttpClient client = new OkHttpClient();
  • 2.创建Request对象
    Request request = new Request.Builder().url("http://xxx").build();
    //builder模式的作用就是将一个复杂对象的构建与他的表示像分离,这样就可以是同样的构建过程创建不同的的表示
  • 3.okttp3.Response response = client.newCall(request).execute();
    • newCall()里面是 return new RealCall(this.request,false);
        RealCall类中方法;
        public Response execute()throw IOException {
            synchronized(this){
            //检查
            if(executed) throw new IllegalStateException("Already Executed")
            executed = true;
            }
            //每个call只能执行一次,如果想要一个完全的方法,可以使用call.clone方法
            captureCallStackTrace();
            try{
                client.dispatcher().executed(this);//开始同步请求
                //dispatcher官方文档中它是一个异步请求的策略,但是它也能做一些同步请求的操作
                Response result = getResponseWithInterceptorChain();
                //okhttp最精髓的地方,拦截器。经过拦截器拦截后,会返回一个response结果给我们的http
                if(result = null) throw new IOException("Canceled");
                return result;
            }finally{
                client.dispathcher().finished(this);
                //通知我们的dispatcher 任务完成
            }
        }
        //以下finished的源码
            finished(runningSyncCalls,call,false);
            即
            private <T> void finished(Deque<T> calls,T call,boolean promoteCalls){
                int runningCallsCount;
                Runnable idleCallback;
                synchronized(this){
                    if(!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
                    if(promoteCalls) promoteCalls();
                    runningCallsCount = runningCallsCount();
                    idleCallback = this.idleCallback;
                }
                if(runningCallsCount == 0 && idleCallback !=null){
                    idleCallback.run();
                }
            }

//做的工作:把请求队列关闭
在同步操作中,client.dispatcher().executed(this)中涉及到dispatcher并不是真正的去做异步操作,只是告诉我们执行的状态。开始执行时executed,执行完了finished方法

真正做网络请求并返回结果的是方法getResponseWithInterceptorChain();

        Response getResponseWithInterceptorChain() throw IOExption{
            List<Interceptor> interceptors = new ArrayList<>();
            interceptors.addAll(client.interceptors);
            interceptors.add(retryAndrFollowUpInterceptor);
            interceptors.add(new BirdgeInterceptor(client.cookieJar()));
            interceptors.add(new CacheInterceptor(client.internalCache()));
            interceptors.add(new ConnectInterceptor(client));
            
            if(!forWebSocket){
                interceptors.addAll(client.networkInterceptors());
            }
            interceptors.add(new CallServerInterceptor(forWebSocket));
            Intercepor.Chain chain = new RealInterceptorChain(interceptors,null,null,null,0,originalRequest);
            return chain.proceed(originalRequest);
        }

interceptor 它把网络请求缓存,压缩等所有功能都统一起来,每一个都是interceptor,连接起来成了一个interceptor.chain

  • 各拦截器
    retryAndrFollowUpInterceptor -->失败重试,重定向,重定向另外一个url
    BirdgeInterceptor 为了把用户构造的请求转换成发送到服务器的请求,然后把服务器的响应转回给用户,进行一些友好输出的响应,这是一个桥接的interceptor
    CacheInterceptor :缓存拦截器,读取,更新缓存
    ConnectInterceptor :和服务端进行连接的拦截器
    CallServerInterceptor :网络的服务器端的连接
        具体分析一个拦截器:
            CallServerInterceptor
            类结构
            +boolean forWebSocket:构造赋值
            --------------------
            public Response intercept(Chain chain) throws IOExcetion{
                
            }
  • 主要作用,向服务器发送一个头部,如果有body也会发送。发送之后获取response的头部和body
  • 其中httpCodec.writeRequestHeaders(request),需要关注httpCodec它的内部是Okio对象 ,okio封装了socket;
  • interceptor设计是一个分层的思想,每一个interceptor就是一层,这是tcp/ip协议是异曲同工之秒、
  • 每一层简化了,每一层只关心每一层的事情,比如CallServerInterceptor只关心和服务器的连接;
    把各种复杂的任务拆分成一个一个独立的任务,这样对以后的拓展很有帮助。

异步请求源码分析

        enqueue也是在RealCall里面处理的
        public void enqueue(Callback responseCallback){
            //同上检查是否已执行
            captureCallStackTrace();
            client.dispatcher().enqueue(new AsyncCall(responseCallback));
        }
        
        Dispatcher 的enqueue方法:
        synchronized void enqueue(AsyncCall call){
            if(runningAsyncCalls.size()<maxREquests && runningCallsForHost(call) < maxRequestsPerHost){
                runningAsyncCalls.add(call);//满足要求添加到队列里面
                executorService().execute(call);
            }else{
                readyAsyncCalls.add(call);
            }
        }
        

类中有是三个集合

        Dequeue<AsyncCall> readyAsyncCalls = new ArrayQeueue<>();//正在准备的异步请求
        Dequeue<AsyncCall> runningAsyncCalls = new ArrayQeueue<>();
        //正在运行的异步请求
        Dequeue<AsyncCall> runningSyncCalls  = new ArrayQeueue<>();//
        //正在运行的同步请求
        executorService() 返回一个线程池(java当中的一个并发类)
            if(executorService == null){
                executorService = new ThreadPoolExecutor(0,Integer.MAIN_VALUE,60,TimeUnit.SECONDS,NEW SynchronourQueue<Runnable>(),Util.threadFactory("OkHttp Dispatcher",false));
            }
            return executorService;

总结

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

推荐阅读更多精彩内容