这里的cache storage 采用ehcache,而不是默认的内存式的cache storage。采用ehcache可以将内容缓存到磁盘上。
maven
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient-cache</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.8.3</version> </dependency>
ehcache配置如下:
<ehcache> <!-- <diskStore path="java.io.tmpdir" /> --> <diskStore path="c:\ehcache"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="httpCache" maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="true" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
这里有两个关键点:一是将eternal设置为true,表示采用非内存式的缓存;二是将diskPersistent设置为true,表示将缓存持久化到硬盘。
测试的代码如下:
package my.httpClient; import java.io.IOException; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.config.CacheConfiguration; import net.sf.ehcache.config.Configuration; import net.sf.ehcache.config.DiskStoreConfiguration; import net.sf.ehcache.config.PersistenceConfiguration; import net.sf.ehcache.config.PersistenceConfiguration.Strategy; import net.sf.ehcache.store.MemoryStoreEvictionPolicy; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.cache.CacheResponseStatus; import org.apache.http.client.cache.HttpCacheContext; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.cache.CacheConfig; import org.apache.http.impl.client.cache.CachingHttpClients; import org.apache.http.impl.client.cache.ehcache.EhcacheHttpCacheStorage; public class EhCacheTest1 { public static void main(String[] args) throws ClientProtocolException, IOException { System.out.println("begin"); // EhCache缓存存储 CacheManager cacheManager = CacheManager.create(); Cache httpCache = cacheManager.getCache("httpCache"); // 定义httpclient的缓存存储 EhcacheHttpCacheStorage ehcacheHttpCacheStorage = new EhcacheHttpCacheStorage( httpCache); // 缓存配置 CacheConfig cacheConfig = CacheConfig.custom() .setMaxCacheEntries(10000).setMaxObjectSize(819200).build(); RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(30000).setSocketTimeout(30000).build(); HttpHost proxy = new HttpHost("127.0.0.1", 8888); CloseableHttpClient cachingClient = CachingHttpClients.custom() .setCacheConfig(cacheConfig) .setHttpCacheStorage(ehcacheHttpCacheStorage) .setDefaultRequestConfig(requestConfig).setProxy(proxy).build(); HttpCacheContext context = HttpCacheContext.create(); HttpGet httpget = new HttpGet("http://test.cn:11677/api/values?id=8888"); CloseableHttpResponse response = cachingClient .execute(httpget, context); try { CacheResponseStatus responseStatus = context .getCacheResponseStatus(); switch (responseStatus) { case CACHE_HIT: System.out .println("A response was generated from the cache with " + "no requests sent upstream"); break; case CACHE_MODULE_RESPONSE: System.out .println("The response was generated directly by the " + "caching module"); break; case CACHE_MISS: System.out.println("The response came from an upstream server"); break; case VALIDATED: System.out.println("The response was generated from the cache " + "after validating the entry with the origin server"); break; } } catch (Exception e) { // TODO: handle exception } finally { response.close(); cacheManager.shutdown(); System.out.println("end"); } } }
以上代码有几个需要说明的地方:
(1)服务端需要遵循RFC2626中规定缓存方面的协议。
(2)代码setHttpCacheStorage(ehcacheHttpCacheStorage)用于设置缓存存储。
(3)代码setProxy(proxy)用于配置代理,当你使用fiddler进行调试的时候,这个很有用。若不采用代理,则可以将这句给去掉。
(4)代码cacheManager.shutdown()用于关闭cacheManager,记得一定要执行这一句,否则会报错。