学习使用Guava Cache
官方文档:https://github.com/google/guava/wiki/CachesExplained
目录
二、快速入门
2.1、引入依赖
2.2、第一个示例
2.3、批量操作
三、拓展
3.1、移除监听器
3.2、刷新缓存
3.3、自定义刷新的操作
一、guava cache介绍
对于常见的cache(缓存),比如memecache、redis、tair这些中间件,也有jdk的一些类库可以当做缓存使用,比如实现了ConcurrentMap接口的ConcurrentHashMap。
ConcurrentHashMap虽然可以让我们在程序中缓存一些数据,但是这些数据其实永远不会过期,除非手动删除,否则数据将一直存在于内存中。
而guava cache(LocalCache,本地缓存),也是实现了ConcurrentMap的类,但他和ConcurrentHashMap的区别在于,guava cache可以设置数据过期以及淘汰机制,更加符合一般的应用需求。
guava cache,是一个本地缓存,也就是说,他的数据是存放在机器内存,这个机器,就是JVM所在的机器(会占用一部分内存),而不是像redis那样专门做缓存的机器。
二、快速入门
2.1、引入依赖
guava cahce是guava的子模块。
guava仓库地址:https://mvnrepository.com/artifact/com.google.guava/guava
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
2.2、第一个示例
下面是一个简单的示例:
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testLoadingCache() throws ExecutionException {
// 创建缓存(容器)
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
// 数据写入1分钟后失效
.expireAfterWrite(1, TimeUnit.MINUTES)
// 支持缓存项的数据最大为3个
.maximumSize(3)
// 实现CacheLoader,当在缓存中未找到所需的缓存项时,会执行CacheLoader的load方法加载缓存。
.build(new CacheLoader<String, String>() {
// 方法的返回值会被缓存,注意,返回null时,会抛异常
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); // 加入缓存
cache.put("Java", "spring");
cache.put("PHP", "swoole"); // 从缓存中获取值
String res1 = cache.get("Java"); // get方法需要抛出ExecutionException异常
// cache.getUnchecked("Java"); // 功能和get一样,但是不会throw异常
System.out.println(res1);
// 输出:spring // 缓存中为存放key为Golang的缓存项,所以进行加载
String res2 = cache.get("Golang");
System.out.println(res2);
// key:Golang 未找到,开始加载....
// Golang-Golang // Golang的缓存项前面已经加载过了,且没有被清除,所以这次直接获取到对应的value
String res3 = cache.get("Golang");
System.out.println(res3);
// Golang-Golang // 前面添加了3个缓存项(已经达到设置上限,此时再添加缓存项,将会触发淘汰)
cache.put("Node", "KOA");
System.out.println(cache.get("PHP")); // PHP在cache中已被淘汰
// key:PHP 未找到,开始加载....
// PHP-PHP // 查询缓存,如果未找到,不会触发加载操作,而是范围null。
String res4 = cache.getIfPresent("key");
System.out.println(res4); // null
}
}
2.3、批量操作
guava cache支持批量添加、查询、清除操作。
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import org.junit.Test; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testMultiple() throws ExecutionException {
// 创建缓存
LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
.maximumSize(2) // 最大缓存项数量为2
.expireAfterWrite(10, TimeUnit.SECONDS) // 数据写入10秒过期
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); Map<String, String> map = new HashMap<>();
map.put("one", "111111");
map.put("two", "222222");
map.put("three", "3333333");
// 批量添加
loadingCache.putAll(map); List<String> keys = new ArrayList<>();
keys.add("one");
keys.add("two");
// 批量获取
ImmutableMap<String, String> allData = loadingCache.getAll(keys);
System.out.println(allData);
// {one=one-one, two=222222} // 批量清除
loadingCache.invalidateAll(keys);
loadingCache.invalidateAll(); // 全量清除
}
}
三、拓展
3.1、移除监听器
移除监听器,是指监听缓存项,当缓存项被清除时,执行指定对操作。
package cn.ganlixin.guava; import com.google.common.cache.*;
import org.junit.Test; import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testRemoveListender() { LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
.expireAfterWrite(1, TimeUnit.MINUTES)
// 绑定"移除监听器",当元素被清除时,执行onRemoval方法
.removalListener(new RemovalListener<String, String>() {
@Override
public void onRemoval(RemovalNotification removalNotification) {
Object key = removalNotification.getKey();
Object val = removalNotification.getValue();
System.out.println("被清除的元素,key:" + key + ", val:" + val); }
})
// 当在缓存中未找到key时,执行load操作。
.build(new CacheLoader<String, String>() {
// 当key未找到时,执行的加载操作
@Override
public String load(String key) throws Exception {
System.out.println("未找到key:" + key + ",开始加载...");
return key + key;
}
}); cache.put("one", "111111");
cache.put("two", "123456"); // 继续添加元素,会触发清理操作,触发移除监听器
cache.put("three", "2233333");
// 输出:被清除的元素,key:one, val:111111 String res = cache.getUnchecked("four");
System.out.println(res);
// 输出
// 未找到key:four,开始加载...
// 被清除的元素,key:two, val:123456
// fourfour
}
}
3.2、刷新缓存
刷新缓存,是指一个缓存项写入缓存后,经过一段时间(设置的刷新间隔),再次访问该缓存项的时候,会刷新该缓存项,可以理解为将该项的key取出,执行CacheLoader的load方法,然后将返回值替换旧的值。
可以在创建缓存的时候,设置刷新缓存的时间:
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testRefresh() throws InterruptedException, ExecutionException {
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
// 设置刷新的时机
.refreshAfterWrite(2, TimeUnit.SECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
}
}); cache.put("one", "11111");
cache.put("two", "22222"); // 休眠3秒
Thread.sleep(3000L); System.out.println(cache.get("one"));
//key:one 未找到,开始加载....
//one-one System.out.println(cache.get("two"));
//key:two 未找到,开始加载....
//two-two
}
}
需要注意的是,以上面代码为例,并不是设置写入2秒后,就会被刷新,而是当写入2秒后,且再次被访问时,才会被刷新;如果一个缓存项写入的时间超过2秒,但是一直没有访问该项,那么这一项是不会被刷新的。这与Memecache和Redis的原理类似。
3.3、自定义刷新缓存的操作
前面内容中,提到可以使用设置refreshAfterWrite()设置数据写入多久后,再次被访问时,会被刷新,其实,我们可以对于刷新操作自定义,只需要重写CacheLoader的reload方法即可。
package cn.ganlixin.guava; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.Test; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; public class UseCache { @Test
public void testReload() throws InterruptedException {
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
// 设置刷新的时机
.refreshAfterWrite(2, TimeUnit.SECONDS)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("key:" + key + " 未找到,开始加载....");
return key + "-" + key;
} // 刷新缓存时,执行的操作
@Override
public ListenableFuture<String> reload(String key, String oldValue) throws Exception {
System.out.println("刷新缓存项,key:" + key + ", oldValue:" + oldValue);
return super.reload(key, oldValue);
}
}); cache.put("hello", "world");
Thread.sleep(3000L); System.out.println(cache.getUnchecked("hello"));
// 刷新缓存项,key:hello, oldValue:world
// key:hello 未找到,开始加载....
// hello-hello
}
}
学习使用Guava Cache的更多相关文章
- spring boot guava cache 缓存学习
http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...
- Guava学习笔记:Guava cache
缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间. 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用 ...
- guava cache学习
Guava Cache与ConcurrentMap很相似,但也不完全一样.最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除.相对地,Guava Cache为了限制内存占 ...
- Spring cache简单使用guava cache
Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...
- 是什么让spring 5放弃了使用Guava Cache?
一路走来,Spring社区从刚开始的核心模块一直发展到现在,最近Sping5也完成了M5的发布, 相信不久之后第一个RELEASE版本也会发布.里面有很多特性是和即将要发布的JAVA 9息息相关的.今 ...
- Guava Cache探索及spring项目整合GuavaCache实例
背景 对于高频访问但是低频更新的数据我们一般会做缓存,尤其是在并发量比较高的业务里,原始的手段我们可以使用HashMap或者ConcurrentHashMap来存储. 这样没什么毛病,但是会面临一个问 ...
- Spring配置cache(concurrentHashMap,guava cache、redis实现)附源码
在应用程序中,数据一般是存在数据库中(磁盘介质),对于某些被频繁访问的数据,如果每次都访问数据库,不仅涉及到网络io,还受到数据库查询的影响:而目前通常会将频繁使用,并且不经常改变的数据放入缓存中,从 ...
- Guava Cache详解
适用性 缓存在很多场景下都是相当有用的.例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存 Guava Cache与ConcurrentMap很相似,但也不 ...
- [Java 缓存] Java Cache之 Guava Cache的简单应用.
前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...
随机推荐
- demo4j解析xml
1//先加入dom4j.jar包 2import java.util.HashMap; 3import java.util.Iterator; 4import java.util.Map; 5 6im ...
- Django+Ajax+Mysql实现数据库数据的展示
最近老师让搞一个系统,仅仅展示一下数据库的数据 在做海底捞时,是交接的师兄的项目,用的语言是java,框架是SSM(Spring.SpringMVC.MyBatis),这次我准备用Python写,前端 ...
- idea 创建项目没有web.xml文件,如何添加
1.首先看下项目工程里面是否有WEB-INF文件夹,没有就创建一个 2.点击 file 选择 project structure 3.选择 facets,点击+号, 选择 web 4.弹出 弹框 选择 ...
- ReactJS - 组件的生命周期
组件的生命周期分为三个状态 Mounting: 已插入真实DOM Updateing: 正在被重新渲染 Unmounting: 已移出真实DOM React 为每个状态都提供了两种处理函数,即函数在进 ...
- Android USB应用开发指南
调试 USB接口被占用后使用wifi调试模式 详见:https://blog.csdn.net/u013758456/article/details/78911812 开发
- RabbitMQ传输原理、五种模式
本文代码基于SpringBoot,文末有代码连接 .首先是一些在Spring Boot的一些配置和概念,然后跟随代码看下五种模式 MQ两种消息传输方式,点对点(代码中的简单传递模式),发布/订阅(代码 ...
- cxf整合spring代码
导入jar包cxf的jar包 创建实体类 package com.yhd.webservice.cxf.server.poto; public class Person { private Strin ...
- 2015-09-23-Archlinux的一些配置
firefox的flash插件 pacman -S flashplugin firefox上网慢 由于Chromium浏览器,打字的时候经常会跳字母,所以就换了firefox浏览器,但是FF上网的时候 ...
- Java开发面试常见问题合集
次面试事故 面试官:你看过哪些源码?我:都挺熟悉的面试官:对hashMap了解程度怎么样?面试官:那你能讲讲 HashMap的实现原理吗?面试官:HashMap什么时候会进行 rehash?面试官:结 ...
- python--防止SQL注入
from pymysql import * def main(): # 创建Connextion连接 conn = connect(host='localhost', port=3306, user= ...