okHttp网络请求

来源:互联网 发布:winner知乎 编辑:程序博客网 时间:2024/04/29 03:50

一,异步OkHttp请求示例

private void testOkHttp() throws IOException {        final OkHttpClient client = new OkHttpClient();        final Request request = new Request.Builder().url("https://www.google.com.hk").build();        Call call = client.newCall(request);        call.enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {            }            @Override            public void onResponse(Call call, Response response) throws IOException {                    Log.i(TAG,response.toString());                    Log.i(TAG,response.body().string());            }        });    }

上面的代码就实现了一个网络请求. 创建一个OkHttpClient对象,他包含了分发器,连接池,拦截器等等内容. 接下来创建一个请求对象,通过OkHttpClient的newCall()方法对其包装,然后添加请求队列,然后回调结果

Tip
对于OkHttpClient封装一个单实例,让所有的Http请求都重用它, OkHttp将会有更好的性能.因为每一个OkHttpClient实例都持有自己的连接池,线程池等,重用连接池和线程池能够减少网络访问延迟以及节省内存,减少资源的浪费

下面我们就详细的分析一下OkHttp详细的网络访问流程

二,OkHttp详访流程

1,创建HttpClient对象.

public OkHttpClient() {    this(new Builder());  }  OkHttpClient(Builder builder) {    this.dispatcher = builder.dispatcher;    this.proxy = builder.proxy;    this.protocols = builder.protocols;    this.connectionSpecs = builder.connectionSpecs;    this.interceptors = Util.immutableList(builder.interceptors);    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);    this.proxySelector = builder.proxySelector;    this.cookieJar = builder.cookieJar;    this.cache = builder.cache;    this.internalCache = builder.internalCache;    this.socketFactory = builder.socketFactory;    ... ...    this.proxyAuthenticator = builder.proxyAuthenticator;    this.authenticator = builder.authenticator;    this.connectionPool = builder.connectionPool;    this.dns = builder.dns;    this.followSslRedirects = builder.followSslRedirects;    this.followRedirects = builder.followRedirects;    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;    this.connectTimeout = builder.connectTimeout;    this.readTimeout = builder.readTimeout;    this.writeTimeout = builder.writeTimeout;    this.pingInterval = builder.pingInterval;  }

由上面可知HttpClient创建的时候,初始化了连接池,线程池,默认拦截器等等,为接下来的网络请求铺垫

2,创建Request对象
1)

Request request = new Request.Builder().url("https://www.google.com.hk").build();

通过Request中的Builder构建一个请求对象
这个Request对象我们可以理解成一个请求Bean,里面封装了请求的url, 请求方法(post get put delete等),请求头,请求体,以及tag(用于批量取消)

 public Call newCall(Request request) {    return new RealCall(this, request, false /* for web socket */);  }

接下来继续对Request对象进行包装,使其能够执行execute,入队enqueue, 取消cancel, 判断状态 isCancel和isExecuted
上面的call指向的是RealCall对象
我们看下Call接口

public interface Call extends Cloneable {  Request request();  Response execute() throws IOException;  void enqueue(Callback responseCallback);  void cancel();  boolean isExecuted();  boolean isCanceled();  Call clone();  interface Factory {    Call newCall(Request request);  }}

3,将请求入队

@Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    client.dispatcher().enqueue(new AsyncCall(responseCallback));  }

OkHttpClient的dispatcher()方法返回的是一个Dispatcher对象,每个Dispatcher使用线程池来运行上面的Call任务.

接下来我们看下Dispacher的入队操作

synchronized void enqueue(AsyncCall call) {    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {      runningAsyncCalls.add(call);      executorService().execute(call);    } else {      readyAsyncCalls.add(call);    }  }

runningAsyncCalls存放所有正在执行的异步任务
readyAsyncCalls存放所有正在等待执行的异步任务
当正在执行的请求小于最大请求数64且每个主机的最大请求数不超过5 则直接加入到正在执行的异步队列中且执行.
否则加入到正在等待执行的异步队列中等待执行.

由上我们可知
请求相同主机的最大请求数目是5
所有请求最大数目是64
实际开发中,用户量一般的app服务器只有一个,那么一般最大的请求就是5 

好了,一个请求封装准备了这么多, 顺利入队,下面我们看看他下面是怎么执行的

4,执行
RealCall封装了原始的Request,在RealCall中有一个非静态内部类AsyncCall,AsyncCall中的execute方法就是任务要执行的代码

final class AsyncCall extends NamedRunnable {   ... ...   ... ...    @Override protected void execute() {      boolean signalledCallback = false;      try {        Response response = getResponseWithInterceptorChain();        if (retryAndFollowUpInterceptor.isCanceled()) {          signalledCallback = true;          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));        } else {          signalledCallback = true;          responseCallback.onResponse(RealCall.this, response);        }      } catch (IOException e) {        if (signalledCallback) {          // Do not signal the callback twice!          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);        } else {          responseCallback.onFailure(RealCall.this, e);        }      } finally {        client.dispatcher().finished(this);      }    }  }

通过getResponseWithInterceptorChain方法 获取到Response对象,下面我们看下他的拦截链

Response getResponseWithInterceptorChain() throws IOException {    // Build a full stack of interceptors.    List<Interceptor> interceptors = new ArrayList<>();    interceptors.addAll(client.interceptors());    interceptors.add(retryAndFollowUpInterceptor);    interceptors.add(new BridgeInterceptor(client.cookieJar()));    interceptors.add(new CacheInterceptor(client.internalCache()));    interceptors.add(new ConnectInterceptor(client));    if (!forWebSocket) {      interceptors.addAll(client.networkInterceptors());    }    interceptors.add(new CallServerInterceptor(forWebSocket));    Interceptor.Chain chain = new RealInterceptorChain(        interceptors, null, null, null, 0, originalRequest);    return chain.proceed(originalRequest);  }RealInterceptorChain.javapublic Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,      Connection connection) throws IOException {   ... ...    //取出下一个拦截器,递归调用    RealInterceptorChain next = new RealInterceptorChain(        interceptors, streamAllocation, httpCodec, connection, index + 1, request);    Interceptor interceptor = interceptors.get(index);    Response response = interceptor.intercept(next);  ... ...    return response;  }

1)首先添加用户自定义的拦截器(如果有),接着依次添加重试拦截器,桥接拦截器,缓存拦截器,连接拦截器以及访问服务器的拦截器.
这些拦截器的添加顺序是固定的,不能改变
2)这些拦截器形成一个拦截链,每个拦截器专司其自己的职责, 将处理好的请求交给下一个拦截器,最后一个拦截器处理完毕后,再将其交给上一个拦截器,直到第一个, 最后将结果返回.这样一个责任链就形成了
3)每个拦截器都实现Interceptor接口

public interface Interceptor {  Response intercept(Chain chain) throws IOException;  interface Chain {    Request request();    Response proceed(Request request) throws IOException;    Connection connection();  }}

4)对于拦截器之间的调用过程可能不太容易理解,下面针对2)给出一个示意图
Req: 请求Request缩写
Res: 响应Response缩写


基本流程图.png

5,结果回调
我们再将目光回到AsyncCall类

    @Override protected void execute() {      boolean signalledCallback = false;      try {        Response response = getResponseWithInterceptorChain();        if (retryAndFollowUpInterceptor.isCanceled()) {          signalledCallback = true;          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));        } else {          signalledCallback = true;          responseCallback.onResponse(RealCall.this, response);        }      } catch (IOException e) {        if (signalledCallback) {          // Do not signal the callback twice!          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);        } else {          responseCallback.onFailure(RealCall.this, e);        }      } finally {        client.dispatcher().finished(this);      }    }  }

当通过getResponseWithInterceptorChain()一系列的处理得到结果后.
1),会首先判断结果是否取消, 如果取消则回调传入的回调onFail中
否则,回调结果到onResponse中
2),接下来是扫尾操作
调用Dispatcher的finish方法

void finished(AsyncCall call) {    finished(runningAsyncCalls, call, true);  }  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();    }  }

它主要做了两件事儿
A,将刚才已经完成的任务从runningAsyncCalls移除
B,如果runningAsyncCall小于5(每个主机的最大访问数量), 则从readyAsyncCalls移除添加到runningAsyncCalls中,并且执行

至此一个完整的OkHttp异步请求完毕
总的来说: 就是根据请求的url, 请求方法, 请求体构造一个Request的Bean, 然后将Request封装成一个RealCall,RealCall实现了Call接口,他有对执行逻辑的操作(取消,执行,判断执行的状态等), 接下来通过全局的OkHttpClient(拥有线程池,连接池,分发器等资源),利用分发器Dispatcher加入到执行队列或者等待队列中.
然后线程池执行RealCall的非静态内部类AsyncCall的execute方法, 然后通过getResponseWithInterceptorChain来进行一系列的拦截器操作处理,回调请求结果.
最后进行扫尾操作,移除正在执行队列的当前请求,将等待队列的请求添加到执行队列.

OkHttp的处理核心是在拦截器,每个拦截器都有自己的职责,下一篇文章详细分析各个拦截器具体都干了什么

0 0
原创粉丝点击