如何使用Guava缓存HTTP响应? (没有线程被阻止)

时间:2018-07-09 11:43:43

标签: java retrofit guava rx-java2 okhttp

所以我试图使用Guava缓存来缓存HTTP响应(使用OkHtttp +改进,rxjava用于多线程)。当前看起来像:

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://blablabla.com")
            .client(client)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    apiClient = retrofit.create(Api.class);

    CacheLoader<Integer, HttpResponse> cacheLoader = new CacheLoader<Integer, HttpResponse>() {
        @Override
        public Response load( Integer key ) throws InterruptedException, ExecutionException {
            return apiClient.getHttpResponse(key)
                    .subscribeOn(Schedulers.io())
                    .blockingFirst();
        }
    };

    responseCache = CacheBuilder.newBuilder()
            .concurrencyLevel(8)
            .maximumSize( 10 )
            .build(cacheLoader);

apiClient返回Observable,并在CacheLoader的load方法中进行预订。我还设置了concurrencyLevel(8),但似乎不允许同时“加载”和“读取”。

我认为blockingFirst()调用可能会阻塞线程,因此我无法从缓存发出并发请求,即,只要缓存加载新的http响应,就无法读取缓存。

我不知道如何使其异步,不胜感激:)

1 个答案:

答案 0 :(得分:0)

使用Guava,您仍然可以进行异步非阻塞调用并缓存HTTP响应,但是在收到HTTP响应后,您将必须手动调用cache.put()。因此,您可以像下面定义您的LoadingCache。

private LoadingCache<String, ServerResponse> cache =
    CacheBuilder.newBuilder()
        .maximumSize(50)
        .expireAfterWrite(24, TimeUnit.HOURS)
        .build(
            new CacheLoader<String, ServerResponse>() {
                public ServerResponse load(String id) {
                    return null; // or empty ServerResponse
                }
            });

在您的调用方法中:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://blablabla.com")
        .client(client)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .build();

apiClient = retrofit.create(Api.class);

try {
    ServerResponse cachedResponse = cache.get(someUniqueKey);
    if (cachedResponse != null) {
        // return cachedResponse here
        return;
    }
    doNormalHttpRequest()
} catch (ExecutionException | CacheLoader.InvalidCacheLoadException e) {
    doNormalHttpRequest();
}

void doNormalHttpRequest() {
    apiClient.request(body).enqueue(
        new retrofit2.Callback<ServerResponse>() {
            @Override
            public void onResponse(Call<ServerResponse> call,
                Response<ServerResponse> response) {
                if (response.isSuccessful()) {
                    cache.put(someUniqueKey, response.body();
                }
            }

            @Override
            public void onFailure(Call<ServerResponse> call, Throwable {}
    });
}

此外,由于改型仅使用OkHttp的缓存实现来缓存GET请求,因此它还可以缓存POST请求。