缘起

看了官方的关于Guava Cache的介绍,感觉太过于啰嗦,我个人是很不喜欢,看了好大半天也看不懂,直到翻到了一篇国内的文章才看懂,特此记录,以备查阅。

如何使用Cache
Cache<String,String> cache = CacheBuilder.newBuilder().build();
public void test() {
    cache.put("word","Hello Guava Cache");
    System.out.println(cache.getIfPresent("word"));
}

看到Cache非常类似于JDK中的Map,但是相比于Map,Guava Cache提供了很多更强大的功能。

自动加载

Cache的get方法有两个参数,第一个参数是要从Cache中获取记录的key,第二个记录是一个Callable对象。当缓存中已经存在key对应的记录时,get方法直接返回key对应的记录。如果缓存中不包含key对应的记录,Guava会启动一个线程执行Callable对象中的call方法,call方法的返回值会作为key对应的值被存储到缓存中,并且被get方法返回。Guava可以保证当有多个线程同时访问Cache中的一个key时,如果key对应的记录不存在,Guava只会启动一个线程执行get方法中Callable参数对应的任务加载数据存到缓存。当加载完数据后,任何线程中的get方法都会获取到key对应的值。

String value = cache.get("key", new Callable<String>() {
    public String call() throws Exception {
        System.out.println("load1"); //加载数据线程执行标志
        Thread.sleep(1000); //模拟加载时间
        return "auto load by Callable";
    }
});

设置最大存储

Cache<String,String> cache = CacheBuilder.newBuilder()
        .maximumSize(2)
        .build();
        
cache.put("key1","value1");
cache.put("key2","value2");
cache.put("key3","value3");
System.out.println("第一个值:" + cache.getIfPresent("key1"));
System.out.println("第二个值:" + cache.getIfPresent("key2"));
System.out.println("第三个值:" + cache.getIfPresent("key3"));

设置过期时间

在构建Cache对象时,可以通过CacheBuilder类的expireAfterAccess和expireAfterWrite两个方法为缓存中的对象指定过期时间,过期的对象将会被缓存自动删除。其中,expireAfterWrite方法指定对象被写入到缓存后多久过期,expireAfterAccess指定对象多久没有被访问后过期。

Cache<String,String> cache = CacheBuilder.newBuilder()
        .maximumSize(2)
        .expireAfterWrite(3,TimeUnit.SECONDS)
        .build();

弱引用

可以通过weakKeys和weakValues方法指定Cache只保存对缓存记录key和value的弱引用。这样当没有其他强引用指向key和value时,key和value对象就会被垃圾回收器回收。

Cache<String,Object> cache = CacheBuilder.newBuilder()
            .maximumSize(2)
            .weakValues()
            .build();

显示清除

可以调用Cache的invalidateAll或invalidate方法显示删除Cache中的记录。invalidate方法一次只能删除Cache中一个记录,接收的参数是要删除记录的key。invalidateAll方法可以批量删除Cache中的记录,当没有传任何参数时,invalidateAll方法将清除Cache中的全部记录。invalidateAll也可以接收一个Iterable类型的参数,参数中包含要删除记录的所有key值。

Cache<String,String> cache = CacheBuilder.newBuilder().build();
Object value = new Object();
cache.put("key1","value1");
cache.put("key2","value2");
cache.put("key3","value3");

List<String> list = new ArrayList<String>();
list.add("key1");
list.add("key2");

cache.invalidateAll(list);//批量清除list中全部key对应的记录

监听器监听移除元素动作

可以为Cache对象添加一个移除监听器,这样当有记录被删除时可以感知到这个事件。

RemovalListener<String, String> listener = new RemovalListener<String, String>() {
    public void onRemoval(RemovalNotification<String, String> notification) {
        System.out.println("[" + notification.getKey() + ":" + notification.getValue() + "] is removed!");
    }
};
Cache<String,String> cache = CacheBuilder.newBuilder()
        .maximumSize(3)
        .removalListener(listener)
        .build();

统计信息

可以对Cache的命中率、加载数据时间等信息进行统计。在构建Cache对象时,可以通过CacheBuilder的recordStats方法开启统计信息的开关。开关开启后Cache会自动对缓存的各种操作进行统计,调用Cache的stats方法可以查看统计后的信息。

Cache<String,String> cache = CacheBuilder.newBuilder()
            .maximumSize(3)
            .recordStats() //开启统计信息开关
            .build();
System.out.println(cache.stats()); //获取统计信息

Guava Cache用法介绍(极简版)_get方法

LoadingCache

LoadingCache是Cache的子接口,相比较于Cache,当从LoadingCache中读取一个指定key的记录时,如果该记录不存在,则LoadingCache可以自动执行加载数据到缓存的操作。

LoadingCache的使用

LoadingCache<String, String> cache = CacheBuilder.newBuilder()
            .build(
                    new CacheLoader<String, String>() {
                        @Override
                        public String load(String key) throws Exception {
                            //在这里可以初始化加载数据的缓存信息,读取数据库中信息或者是加载文件中的某些数据信息
                            return "";
                        }
                    });

与构建Cache类型的对象类似,LoadingCache类型的对象也是通过CacheBuilder进行构建,不同的是,在调用CacheBuilder的build方法时,必须传递一个CacheLoader类型的参数,CacheLoader的load方法需要我们提供实现。当调用LoadingCache的get方法时,如果缓存不存在对应key的记录,则CacheLoader中的load方法会被自动调用从外存加载数据,load方法的返回值会作为key对应的value存储到LoadingCache中,并从get方法返回。

CacheLoader<String, String> loader = new CacheLoader<String, String> () {
    public String load(String key) throws Exception {
        Thread.sleep(1000); //休眠1s,模拟加载数据
        System.out.println(key + " is loaded from a cacheLoader!");
        return key + "'s value";
    }
};

LoadingCache<String,String> loadingCache = CacheBuilder.newBuilder()
        .maximumSize(3)
        .build(loader);//在构建时指定自动加载器

或者也可以结合spring来用

@Bean
public LoadingCache<String, Object> myCacheStorage() {
    return CacheBuilder.newBuilder()
            .build(new CacheLoader<String, Object>() {
                @Override
                public Object load(String name) throws Exception {
                    //在这里可以初始化加载数据的缓存信息,读取数据库中信息或者是加载文件中的某些数据信息
                    return null;
                }
            });
}

@Autowired
LoadingCache<String, Object> loadingCache;