okhttp架构原理剖析

2019-10-29  本文已影响0人  嘉伦哥

简单的架构图

先来看看okhttp 简单的架构,分为6层。每一层都负责各自的任务!下面会对每一层进行简单的剖析!


image.png

1.Interface-接口层

接口层包含:okhttclient、Call、RealCall、AsyncCall、Dispatcher

2.Protocal协议层

Protocol层负责处理协议逻辑,OkHttp支持Http1、Http2、WebSocket协议。

3.Connection-连接层

在连接层中有一个连接池,统一管理所有的Socket连接,当用户新发起一个网络请求时,OkHttp会首先从连接池中查找是否有符合要求的连接,如果有则直接通过该连接发送网络请求;否则新创建一个连接。RealConnection描述一个物理Socket连接,连接池中维护多个RealConnection实例。由于Http/2支持多路复用,一个RealConnection可以支持多个网络访问请求,所以OkHttp又引入了StreamAllocation来描述一个实际的网络请求

rivate RealConnection findConnection(。。。){   
     result = new RealConnection(connectionPool, selectedRoute);
    result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);

}
public void connect(。。。) {
     //如果协议不等于null,抛出一个异常
    if (protocol != null) throw new IllegalStateException("already connected");

   。。 省略部分代码。。。。

    while (true) {//一个while循环
         //如果是https请求并且使用了http代理服务器
        if (route.requiresTunnel()) {
          connectTunnel(...);
        } else {//
            //直接打开socket链接
          connectSocket(connectTimeout, readTimeout);
        }
        //建立协议
        establishProtocol(connectionSpecSelector);
        break;//跳出while循环
        。。省略部分代码。。。
  }

4.Cache-缓存层

在okhttpClient源码中可以发现,内部缓存使用到时一个Cache类

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.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    .....省略代码
    .....省略代码
  }

看一下cache类中的构造方法使用的是DiskLruCache缓存机制

Cache(File directory, long maxSize, FileSystem fileSystem) {
    this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
  }

DiskLruCache 和LruCache 都知道,分别用于实现内存缓存和硬盘缓存,其核心思想都是LRU算法。


private final class Entry {
    final String key;

    /** Lengths of this entry's files. */
    final long[] lengths;
    final File[] cleanFiles;
    final File[] dirtyFiles;

    /** True if this entry has ever been published. */
    boolean readable;

    /** The ongoing edit or null if this entry is not being edited. */
    Editor currentEditor;

    /** The sequence number of the most recently committed edit to this entry. */
    long sequenceNumber;

    Entry(String key) {
      this.key = key;

      lengths = new long[valueCount];
      cleanFiles = new File[valueCount];
      dirtyFiles = new File[valueCount];

      // The names are repetitive so re-use the same builder to avoid allocations.
      StringBuilder fileBuilder = new StringBuilder(key).append('.');
      int truncateTo = fileBuilder.length();
      for (int i = 0; i < valueCount; i++) {
        fileBuilder.append(i);
        cleanFiles[i] = new File(directory, fileBuilder.toString());
        fileBuilder.append(".tmp");
        dirtyFiles[i] = new File(directory, fileBuilder.toString());
        fileBuilder.setLength(truncateTo);
      }
    }

 /**
     * Returns a snapshot of this entry. This opens all streams eagerly to guarantee that we see a
     * single published snapshot. If we opened streams lazily then the streams could come from
     * different edits.
     */
    Snapshot snapshot() {
      if (!Thread.holdsLock(DiskLruCache.this)) throw new AssertionError();

      Source[] sources = new Source[valueCount];
      long[] lengths = this.lengths.clone(); // Defensive copy since these can be zeroed out.
      try {
        for (int i = 0; i < valueCount; i++) {
          sources[i] = fileSystem.source(cleanFiles[i]);
        }
        return new Snapshot(key, sequenceNumber, sources, lengths);
      } catch (FileNotFoundException e) {
        // A file must have been deleted manually!
        for (int i = 0; i < valueCount; i++) {
          if (sources[i] != null) {
            Util.closeQuietly(sources[i]);
          } else {
            break;
          }
        }
        // Since the entry is no longer valid, remove it so the metadata is accurate (i.e. the cache
        // size.)
        try {
          removeEntry(this);
        } catch (IOException ignored) {
        }
        return null;
      }
    }

5.IO层

6.Interceptor-拦截器层

上一篇下一篇

猜你喜欢

热点阅读