1.概述
guava cache是基于java的本地缓存,使用缓存的目的是为了系统响应更快。以下是guava cache中相关的类
2.使用
2.1CacheLoader 创建
使用from方法创建,或者使用构造器,需要实现load方法
CacheLoader getCacheLoader(){
return CacheLoader.from(key->key.toString().toUpperCase());
}
new CacheLoader() {
@Override
public Object load(Object key) throws Exception {
return key.toString().toUpperCase();
}
};
2.2 LoadingCache使用
@Test
public void useLoadingCache() {
CacheLoader<String, String> loader;
loader = getCacheLoader();
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder().build(loader);
assertEquals(0, cache.size());
assertEquals("HELLO", cache.getUnchecked("hello"));
assertEquals(1, cache.size());
}
2.3设置最大缓存数
可以使用CacheBuilderSpec设置,或者使用CacheBuilder.newBuilder().maximumSize(),如下设置最大数为3,当存取第四个是第一个会过期
@Test
public void setCacheMaximumSize() {
CacheLoader<String, String> loader;
loader = getCacheLoader();
LoadingCache<String, String> cache;
//使用CacheBuilderSpec
cache= CacheBuilder.from(CacheBuilderSpec.parse("maximumSize=3")).build(loader);
cache.getUnchecked("first");
cache.getUnchecked("second");
cache.getUnchecked("third");
cache.getUnchecked("forth");
assertEquals(3, cache.size());
assertNull(cache.getIfPresent("first"));
assertEquals("FORTH", cache.getIfPresent("forth"));
}
2.4 设置MaxWeight
达到设置的阈值时,缓存过期。以下实列中权重设置的时缓存值的长度
@Test
public void setCacheMaxWeight() {
CacheLoader<String, String> loader;
loader = getCacheLoader();
Weigher<String, String> weighByLength;
weighByLength = (key, value) -> value.length();
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder()
.maximumWeight(16)
.weigher(weighByLength)
.build(loader);
cache.getUnchecked("first");
cache.getUnchecked("second");
cache.getUnchecked("third");
cache.getUnchecked("last");
assertEquals(3, cache.size());
assertNull(cache.getIfPresent("first"));
assertEquals("LAST", cache.getIfPresent("last"));
2.5 通过时间来过期缓存
expireAfterAccess指访问后单位时间过期,也可以设置expireAfterWrite,即被写后多长时间过期
@Test
public void expireAfterTime()
throws InterruptedException {
CacheLoader<String, String> loader;
loader = getCacheLoader();
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder()
.expireAfterAccess(2, TimeUnit.MILLISECONDS)
.build(loader);
cache.getUnchecked("hello");
assertEquals(1, cache.size());
cache.getUnchecked("hello");
Thread.sleep(300);
cache.getUnchecked("test");
assertEquals(1, cache.size());
assertNull(cache.getIfPresent("hello"));
}
2.6 弱key引用weakKeys
垃圾回收时会对所引用所对应的缓存值回收。
@Test
public void weakKeyHasNoRef() throws InterruptedException {
CacheLoader<MyKey, String> loader=CacheLoader.from(key->key.getKey()+" reference");
LoadingCache<MyKey, String> cache = CacheBuilder.newBuilder().weakKeys().build(loader);
MyKey key = new MyKey("weak");
String value = cache.getUnchecked(key);
assertEquals(value,"weak reference");
key=null;
System.gc();
TimeUnit.SECONDS.sleep(2);
assertEquals(1,cache.size());
System.out.println(cache.asMap());
}
@Data
private static class MyKey{
String key;
public MyKey(String key) {
this.key = key;
}
}
2.7 刷新缓存
可以使用自动刷新和手动刷新
@Test
void refreshCache() throws ExecutionException {
//自动刷新
CacheLoader<String, String> loader;
loader =getCacheLoader();
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder()
.refreshAfterWrite(1,TimeUnit.MINUTES)
.build(loader);
//手动刷新
String value = cache.get("key");
cache.refresh("key");
}
2.8 使用putAll方法
@Test
public void usePutAll() {
CacheLoader<String, String> loader;
loader = getCacheLoader();
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder().build(loader);
Map<String, String> map = new HashMap<>();
map.put("first", "FIRST");
map.put("second", "SECOND");
cache.putAll(map);
assertEquals(2, cache.size());
}
2.9使用Listener 监听缓存的变化
@Test
public void useListener() {
CacheLoader<String, String> loader;
loader = getCacheLoader();
RemovalListener<String, String> listener;
listener = n -> {
if (n.wasEvicted()) {
String cause = n.getCause().name();
assertEquals(RemovalCause.SIZE.toString(),cause);
}
};
LoadingCache<String, String> cache;
cache = CacheBuilder.newBuilder()
.maximumSize(3)
.removalListener(listener)
.build(loader);
cache.getUnchecked("first");
cache.getUnchecked("second");
cache.getUnchecked("third");
cache.getUnchecked("last");
assertEquals(3, cache.size());
}
2.10 使用Forwarding
forwarding相当于对底层缓存的装饰,以便我们可以自己重新缓存实现。
public class LoggingForwardingCache<K, V> extends ForwardingCache.SimpleForwardingCache<K, V> {
private final Logger logger = Logger.getLogger(LoggingForwardingCache.class.getName());
public LoggingForwardingCache(Cache<K, V> delegate) {
super(delegate);
}
@Override
public V getIfPresent(Object key) {
V value = super.getIfPresent(key);
if (value != null) {
logger.info("Cache hit for key: " + key);
}
return value;
}
}
----------------
@Test
public void useForwarding(){
Cache<String, Object> cache =
CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
LoggingForwardingCache<String, Object> loggingCache = new LoggingForwardingCache<>(cache);
loggingCache.put("forward","loggingCache");
Object forward = loggingCache.getIfPresent("forward");
assertEquals("loggingCache",forward);
}
3.总结
在上面的例子中,主要介绍了guava缓存的基本用法,在新版本中也是更新了lamda的方法,所以主要以lamda方式去创建CacheLoader。并且通过junit的静态方法去验证缓存预期是不是正确。