使用Guava作为本地缓存让系统飞起来
简介guava是google的一个开源java框架,其github地址是 https://github.com/google/guava。guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:集合 [collections]缓存 [caching]原生类型支持 [primitives support]并发库 [concurrency libraries]通用注解...
·
简介
guava是google的一个开源java框架,其github地址是 https://github.com/google/guava。guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:
- 集合 [collections]
- 缓存 [caching]
- 原生类型支持 [primitives support]
- 并发库 [concurrency libraries]
- 通用注解 [common annotations]
- 字符串处理 [string processing]
- I/O
所有这些工具每天都在被Google的工程师应用在产品服务中。 其中caching这一块是常用的模块的之一
引入依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
使用示例
基本用法
@Component
public final class WsPlasRoleCache {
private static Logger logger = LoggerFactory.getLogger(WsPlasRoleCache.class);
private static AtomicBoolean isInited = new AtomicBoolean(false);
private static LoadingCache<String, List<WsPlasRole>> cache;
private WsPlasRoleCache() {
if (!isInited.get()) {
init();
}
}
private static void init() {
logger.info("---初始化WsPlasRole");
cache = CacheBuilder.newBuilder().refreshAfterWrite(10, TimeUnit.MINUTES)
.build(new CacheLoader<String, List<WsPlasRole>>() {
@Override
public List<WsPlasRole> load(String key) throws Exception {
// 如果是第一次,调用load方法;如果是两次get时间在10分钟之间,就不会调用load
PlasRoleManager service = SpringContextHolder.getBean("plasRoleManager");
logger.info("查询WsPlasRole");
List<WsPlasRole> list = service.getWsAll(key);
return list;
}
});
isInited.set(true);
}
public static List<WsPlasRole> getWsAll(String key) {
try {
return cache.get(key);
} catch (Exception e) {
}
return null;
}
}
利用@Component让工程启动的时候初始化cache对象,重写构造函数并且设置为private是为了保证是单例的
核心方法
- refreshAfterWrite : 写入数据后多久过期,只阻塞当前数据加载线程,其他线程返回旧值
- expireAfterWrite : 写缓存后多久过期
- expireAfterAccess : 读写缓存后多久过期
- maximumSize : 设置缓存最大容量,超过之后就会按照LRU最近虽少使用算法来移除缓存项
异步刷新
抽象类CacheLoader是同步刷新的。
如果缓存到期了,有多个线程调用缓存,那么第一个调用的会阻塞住,其他的线程会直接返回已过期的缓存
如果想要让所有的线程都不阻塞,就要创建异步加载类
public abstract class RefreshAsyncCacheLoader<K, V> extends CacheLoader<K, V> {
private ExecutorService threadPool = Executors.newSingleThreadExecutor();
@Override
public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception {
checkNotNull(key);
checkNotNull(oldValue);
//增加配置参数,控制是否异步加载;1-异步加载,0-同步加载
String async = PropertyConfigurer.getProperty("cache.refres.async");
if (StringUtils.equals(async,"1")){
ListenableFutureTask<V> task = ListenableFutureTask.create(new Callable<V>() {
public V call() {
try {
return load((K) key);
} catch (Exception e) {
}
return oldValue;
}
});
threadPool.execute(task);
return task;
}else{
return Futures.immediateFuture(load(key));
}
}
}
将CacheLoader替换成异步实现类RefreshAsyncCacheLoader
public static void init() {
logger.info("---初始化WsPlasUserCache");
cache = CacheBuilder.newBuilder().refreshAfterWrite(10, TimeUnit.MINUTES)
.build(new RefreshAsyncCacheLoader<String, List<WsPlasUser>>() {
@Override
public List<WsPlasUser> load(String key) throws Exception {
PlasUserManager service = SpringContextHolder.getBean("plasUserManager");
logger.info("查询WsPlasUser");
List<WsPlasUser> list = service.getWsAll();
return list;
}
});
}
显示清除
缓存会自动过期,也可以手动让其过期,主要有以下方法:
- 个别清除:Cache.invalidate(key)
- 批量清除:Cache.invalidateAll(keys)
- 清除所有缓存项:Cache.invalidateAll()
总结
- guava cache是本地缓存,和redis、memcached等集中缓存不同,如果是集群环境,本地缓存有不同步的问题,如果对缓存同步时间要求不是太高,这完全不是问题
- 相比于redis等集中缓存,本地缓存性能更高;因为没有网络交互,直接内存读取
- guava cache使用简单、控制灵活
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献9条内容
所有评论(0)