第2章 OkHttp内置Cache类初始化与配置

OkHttp的缓存能力由 Cache 类直接提供。理解其构造参数与磁盘布局是正确配置的基础。本章围绕 Cache(directory, maxSize) 构造函数,详细拆解每个参数的含义、默认行为以及缓存文件在磁盘上的组织结构,并给出可复用的初始化模板。

2.1 Cache 构造函数的两个核心参数

Cache 仅有一个公开构造函数,签名如下:

public Cache(File directory, long maxSize)

两个参数的含义与约束:

参数 类型 说明 常见值
directory File 缓存文件存储的目录路径。如果目录不存在,OkHttp 会自动创建(包含必要时创建父目录)。必须是一个可写目录,否则初始化阶段会抛出 IOException。 context.cacheDir / new File("/data/okhttp_cache")
maxSize long 缓存最大字节数。OkHttp 通过 DiskLruCache 进行清理,当总大小超过此值时会淘汰最旧的条目。最小值建议为 1(非零),实际项目中常用 10 * 1024 * 1024(10MB)以上。 50 * 1024 * 1024L
⚠ 注意:maxSize 并非严格上限,OkHttp 会在后台异步清理,实际占用可能短暂超过设定值。建议预留 10%~20% 的缓冲区。

2.2 默认缓存目录与平台差异

OkHttp 没有硬编码的“默认”缓存目录 —— 你必须显式提供一个 File 对象。但在 Android 和 Java 服务端场景下,存在常见约定路径:

  • Android:使用 context.getCacheDir() 或 context.getExternalCacheDir()。内部存储路径一般为 /data/data/<package>/cache/okhttp_cache。
  • Java 服务端:使用 new File("/var/cache/okhttp") 或 Paths.get(System.getProperty("java.io.tmpdir"), "okhttp-cache").toFile()。
// Android 示例
File cacheDir = new File(context.getCacheDir(), "http-cache");
long cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(cacheDir, cacheSize);

2.3 缓存文件结构深度解析

初始化完成后,directory 下会生成以下文件/子目录:

  • journal(核心日志文件):记录所有缓存条目的状态(DIRTY、CLEAN、READ、REMOVE)。是缓存一致性的保障。
  • 条目文件(.0 / .1):每个缓存条目由两个文件组成:<key>.0(元数据,如响应头)和 <key>.1(响应体数据)。键是 URL 的 MD5 哈希。
  • 临时文件(.tmp):写入过程中产生的临时文件,写入完成会被重命名为正式条目文件。

典型磁盘布局(tree 形式):

/cache/okhttp/
├── journal
├── 2a1b3c4d5e6f7890.0
├── 2a1b3c4d5e6f7890.1
├── ffeeddccbbaa9988.0
├── ffeeddccbbaa9988.1
└── ...
💡 调试技巧:检查 journal 文件的前几行可以确认缓存是否正常工作。首行固定为 libcore.io.DiskLruCache,第二行是版本号和应用版本号。

2.4 Cache 初始化流程与文件关系图

Cache 初始化与缓存文件结构 Cache 初始化流程与磁盘文件结构 Cache(directory, maxSize) ▶ 传入 File 和 long 目录检查与创建 mkdirs() 自动创建父目录 DiskLruCache 初始化 打开/创建 journal 文件 磁盘目录结构 /cache/okhttp/ journal (元数据日志) 2a1b3c4d.0 (响应头) 2a1b3c4d.1 (响应体) ...更多 .0 / .1 文件 key 通过 MD5(URL) 生成 .0 存储响应头,.1 存储响应体

2.5 缓存大小限制的工程实践

maxSize 的选取直接关系到缓存命中率和磁盘占用。以下为不同场景的推荐值:

应用类型 推荐 maxSize 理由
轻量App(少量图片API) 5 ~ 10 MB 避免频繁GC与I/O
媒体密集App(图片/视频) 50 ~ 200 MB 覆盖多数重复请求
服务端反向代理 500 MB ~ 数 GB 根据业务QPS与时效性

2.6 常见错误与调试

  • java.io.IOException: No space left on device —— maxSize 设置过大,或磁盘已满。检查剩余空间并调整上限。
  • java.io.FileNotFoundException: ... (Read-only file system) —— 传入的 directory 权限不足。确保路径可写,尤其是 Android 外部存储需要额外权限。
  • 缓存大小无变化 —— 未正确配置 Cache-Control 响应头,OkHttp 不缓存无缓存指令的响应。参见第4章。
🔧 调试常用代码:打印缓存统计信息
Cache cache = okHttpClient.cache();
if (cache != null) {
    System.out.println("缓存命中: " + cache.hitCount());
    System.out.println("缓存请求: " + cache.requestCount());
    System.out.println("网络请求: " + cache.networkCount());
}

2.7 性能与稳定性优化要点

  1. 目录隔离:不同业务线使用独立的 Cache 实例,避免单个大缓存污染。
  2. 写入缓冲:OkHttp 内部使用 BufferedSink 避免频繁小文件 I/O,无需额外配置。
  3. journal 重建:若 journal 文件受损,DiskLruCache 会触发重建,此时读写性能下降。确保进程不强行 kill 写操作。
  4. 文件描述符限制:缓存条目过多时打开大量文件句柄。Linux 可通过 ulimit -n 调整,或适当降低 maxSize 减少条目数。