OkHttp Source Code Analyse (Part one)

来源:互联网 发布:淘宝二手手机评估 编辑:程序博客网 时间:2024/06/05 14:43

OkHttp 

An HTTP & HTTP/2 client for Android and Java applications

HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.

OkHttp is an HTTP client that’s efficient by default:

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.

OkHttp perseveres when the network is troublesome: it will silently recover from common connection problems. If your service has multiple IP addresses OkHttp will attempt alternate addresses if the first connect fails. This is necessary for IPv4+IPv6 and for services hosted in redundant data centers. OkHttp initiates new connections with modern TLS features (SNI, ALPN), and falls back to TLS 1.0 if the handshake fails.

Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks.

OkHttp supports Android 2.3 and above. For Java, the minimum requirement is 1.7.

From:http://square.github.io/okhttp/



Example:

OkHttpClient client = new OkHttpClient();        Request request = new Request.Builder()                .url("www.baidu.com")                .build();                //sync method        Response response = client.newCall(request).execute();        //async method        client.newCall(request).enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {            }            @Override            public void onResponse(Call call, Response response) throws IOException {            }        });


主要分析一下client.newCall(request).enqueue(Callback callback)方法:

(1)client.newCall(Request request);

OkHttpClient.java

/** * Prepares the {@code request} to be executed at some point in the future. */@Override public Call newCall(Request request) {  return new RealCall(this, request);}
protected RealCall(OkHttpClient client, Request originalRequest) {  this.client = client;  this.originalRequest = originalRequest;}


(2)client.newCall(request).enqueue(Callback responesCallback);

RealCall.java

@Override public void enqueue(Callback responseCallback) {  enqueue(responseCallback, false);}void enqueue(Callback responseCallback, boolean forWebSocket) {  synchronized (this) {    if (executed) throw new IllegalStateException("Already Executed");    executed = true;  }  client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));}
(2-1)client.dispatcher();

Dispatcher.java

private int maxRequests = 64;private int maxRequestsPerHost = 5;/** Executes calls. Created lazily. */private ExecutorService executorService;/** Ready async calls in the order they'll be run. */private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();/** Running synchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();public Dispatcher(ExecutorService executorService) {  this.executorService = executorService;}public Dispatcher() {}public synchronized ExecutorService executorService() {  if (executorService == null) {    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,        new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));  }  return executorService;}

可以看出Dispatcher内包含一个TheadPoolExecutor(线程池),负责管理并执行加入其中的任务,

重点区分下面这三个Deque:

readyAsyncCalls:等待执行的任务队列;

runningAsyncCalls:正在执行的异步任务队列;

runningSyncCalls:正在执行的同步阻塞任务队列;


(2-2) client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));

Dispatcher.java

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

可以看出:当向Dispather中加入新的异步任务时,如果当前正在执行的异步任务数小于64并且在所有正在执行的异步任务中与该新任务拥有相同主机名的任务小于5时,直接将该任务加入正在执行的任务队列中,并开始执行它,否则加入等待队列。

(3)线程池执行一个异步任务AsycCall(实际就是一个Runnable),会调用该类的execute()方法;

RealCall.java

@Override protected void execute() {  boolean signalledCallback = false;  try {    Response response = getResponseWithInterceptorChain(forWebSocket);    if (canceled) {      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);  }}

(3-1) Response response = getResponseWithInterceptorChain(forWebSocket);

发送网络请求,并获取响应,后续会详细介绍,获取响应或出现异常 通过Callback responseCallback回调给发送请求方。

(3-2)最后会执行 client.dispatcher().finished(this);

Dispatcher.java

/** Used by {@code AsyncCall#run} to signal completion. */synchronized void finished(AsyncCall call) {  if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");  promoteCalls();}private void promoteCalls() {  if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.  if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {    AsyncCall call = i.next();    if (runningCallsForHost(call) < maxRequestsPerHost) {      i.remove();      runningAsyncCalls.add(call);      executorService().execute(call);    }    if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.  }}

可以看出,在finished(AsyncCall call)中将刚刚完成的AsyncCall从runningAsyncCalls中移除,然后调用promoteCalls()方法;

在promoteCalls()方法中,如果当前正在执行的任务个数大于等于64,表示线程池已经达到最大并发量,不能再加入新任务,退出。如果当前等待队列为空,表示新任务可执行,退出。

否则就遍历readyAsyncCalls,如果某个任务的主机名在正在执行的任务队列的个数小于5 ,则将其从等待队列中移除并加入到runningAsyncCalls中并放入线程池执行,直至线程池达到最大并发量64。


然后,当线程池中的某任务执行完后,再调用Dispather的finished 方法,再从等待任务队列中取出新任务加入到线程池中执行。与此同时,也会有任务不断的加入Dispather中,当线程池中有任务执行完毕后,就会从等待队列中取出任务加入到线程池中执行。


每当有任务执行完毕后,都会主动检测
等待任务队列是否有可执行的任务,而没有使用互斥锁等逻辑,避免发生死锁。


  • OkHttp采用Dispatcher技术,类似于Nginx,与线程池配合实现了高并发,低阻塞的运行
  • Okhttp采用Deque作为缓存,按照入队的顺序先进先出
  • OkHttp最出彩的地方就是在try/finally中调用了finished函数,可以主动控制等待队列的移动,而不是采用锁或者wait/notify,极大减少了编码复杂性
  • 作者:BlackSwift链接:http://www.jianshu.com/p/6637369d02e7來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


    Reference:http://www.jianshu.com/p/6637369d02e7


    阅读全文
    0 0
    原创粉丝点击