okhttp提供缓存机制,用于缓存响应head和body,但默认是不开启缓存机制。
启用缓存:
new OkHttpClient().newBuilder().cache(new Cache(new File(“D:/”), 10240)).build();
缓存执行基本流程:
1.执行拦截器链CacheInterceptor,首先会从缓存中读取响应结果
2.okhttp提供Cache类作为缓存的基本操作类,实际缓存操作是通过该类执行
缓存实现基本原理:
存储:
1.okhttp缓存存储是基于文件存储,从启用缓存机制传入的两个参数也可以看出:directory->缓存文件目录,maxSize->缓存支持存储的最大字节数
清理:
1.缓存清理是基于LRU机制,清理最老且使用最少的数据
2.内部维护一个清理线程,当size大于或等于maxSize时就会执行清理操作
关于缓存文件,可以参考一段源码注释:
- This cache uses a journal file named “journal”. A typical journal file
looks like this:
libcore.io.DiskLruCache
1
100
2
CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
DIRTY 335c4c6028171cfddfbaae1a9c313c52
CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
REMOVE 335c4c6028171cfddfbaae1a9c313c52
DIRTY 1ab96a171faeeee38496d8b330771a7a
CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
READ 335c4c6028171cfddfbaae1a9c313c52
READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
The first five lines of the journal form its header. They are the
constant string “libcore.io.DiskLruCache”, the disk cache’s version,
the application’s version, the value count, and a blank line.
Each of the subsequent lines in the file is a record of the state of a
cache entry. Each line contains space-separated values: a state, a key,
and optional state-specific values.
o DIRTY lines track that an entry is actively being created or updated.
Every successful DIRTY action should be followed by a CLEAN or REMOVE
action. DIRTY lines without a matching CLEAN or REMOVE indicate that
temporary files may need to be deleted.
o CLEAN lines track a cache entry that has been successfully published
and may be read. A publish line is followed by the lengths of each of
its values.
o READ lines track accesses for LRU.
o REMOVE lines track entries that have been deleted.
The journal file is appended to as cache operations occur. The journal may
occasionally be compacted by dropping redundant lines. A temporary file named
“journal.tmp” will be used during compaction; that file should be deleted if
it exists when the cache is opened.
解释:
1.前五行内容描述的是缓存版本信息相关
2.后面每个子行描述的是缓存数据的状态信息及key对应的信息
3.DIRTY lines->跟踪被修改的数据
CLEAN lines->每次的DIRTY操作后面都需要跟一个CLEAN/REMOVE操作,表示执行已完成
READ lines->跟踪每次读取操作
REMOVE lines->跟踪每次删除操作
通过一个简单例子来测试下okhttp缓存机制
完整源码:https://github.com/ingorewho/do-test/tree/master/okhttp-test
配置代码:
/**
* @Author: ignore1992
* @Description: 配置okhttp
* @Date: Created In 17:45 2019/1/30
*/
public class OkhttpConfig {
private static volatile OkHttpClient client = null;
public static OkHttpClient client(){
if (client == null){
synchronized (OkhttpConfig.class){
if (client == null){
client = new OkhttpConfig().init();
}
}
}
return client;
}
public OkHttpClient init(){
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.addInterceptor(new TestInterceptor())
.addInterceptor(new OkInterceptor())
.addNetworkInterceptor(new OkNetInterceptor())
.retryOnConnectionFailure(true)
.cache(new Cache(new File("D:/"), 10240))
.sslSocketFactory(getTrustedSSLSocketFactory())
.hostnameVerifier(DO_NOT_VERIFY);
return builder.build();
}
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
X509Certificate[] x509Certificates = new X509Certificate[0];
return x509Certificates;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
private SSLSocketFactory getTrustedSSLSocketFactory() {
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
return sc.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
}
测试代码:
/**
* @Author: ignore1992
* @Description:
* @Date: Created In 14:48 2019/1/31
*/
public class Main {
public static void main(String[] args) {
//1.重复执行get同步请求,为了方便查看缓存命中信息
System.out.println(ProcessOkhttp.get("https://api.apiopen.top/searchAuthors?name=%E6%9D%8E%E7%99%BD", null));
System.out.println(ProcessOkhttp.get("https://api.apiopen.top/searchAuthors?name=%E6%9D%8E%E7%99%BD", null));
}
}
查看缓存目录下:D:/文件夹下出现三个文件:
journal文件(记录缓存操作记录)
99e43630a8fed826b8b19a06e1b8d09e.0文件(记录header信息)
99e43630a8fed826b8b19a06e1b8d09e.1文件(记录body信息)