spring boot 集成 Guava Cache

2023-05-16

Guava Cache

    • 背景
    • 集成
    • 缓存存放
    • 缓存回收:
      • 基于容量回收(Size-based Eviction)
      • 基于时间回收(Timed Eviction)
      • 基于引用类型的回收(Reference-based Eviction)
      • 手动缓存回收
    • 运维监控缓存
    • 完整例子

背景

Guava Cache 是 Google 开源的一套开发工具集合,Guava Cache 是其中的一个专门用于处理本地缓存的轻量级框架,是全内存方式的本地缓存,而且是线程安全的。和 ConcurrentMap 相比,Guava Cache 可以限制内存的占用,并可设置缓存的过期时间,可以自动回收数据,而 ConcurrentMap 只能通过静态方式来控制缓存,移除数据元素需要显示的方式来移除。下面通过例子来演示Guava Cache 的使用方式:

​ 使用 Guava Cache 的Maven 以来如下,Guava Cache 是 Google Guava 工具库中的一部分,不能单独应用,所以要把整个 Guava 库都引入进来,例如:

集成

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>23.0</version>
</dependency>

缓存存放

​ 在 Guava Cache 中需要通过CacheBuilder创建缓存对象,并通过 CacheLoader 和 Callable 两种方式定义原始数据的获取方式,CacheLoader 是在缓存对象声明时指定,Callable 是在获取数据时指定,相比于 CacheLoader ,Callable 更加灵活,当然也可以通过 cache.put(key,value) 的方式直接插入。

LoadingCache<Long, UserInfo> cache = CacheBuilder.newBuilder()
  // 设置缓存个数
  .maximumSize(1000).build(new CacheLoader<Long, UserInfo>() {
  @Override
  public UserInfo load(Long key) throws Exception {
    return getUserInfoByUserId(key);
  }
});

try {
  // 读取缓存
  UserInfo user = cache.get(100001L);
} catch (ExecutionException e) {
  e.printStackTrace();
  doSomethingForException();
}

下面是通过 CacheLoader 使用缓存的例子:

// 定义缓存
Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(1000).build();

try {
  // 用户id
  final Long userId = 100001L;
  UserInfo user = (UserInfo) cache.get(userId, new Callable<UserInfo>() {
    @Override
    public UserInfo call() throws Exception {
      return getUserInfoByUserId(userId);
    }
  });
} catch (ExecutionException e) {
  doSomethingForException();
}

​ 如果 key 为自定义对象,则需要重写 boolean equals(Object obj) 方法,Guava Cache 默认情况(使用弱引用保存key的情况除外,这种情况按照内存地址进行比较)下按照 equals 方法比较key是否相同。

缓存回收:

​ 内存空间不是无限大的,当没有足够的内存情况下,必须要考虑缓存数据回收的问题,移除旧缓存数据为新的缓存数据腾出空间。
Guava Cache 支持四种回收方式,分别是基于容量回收(Size-based Eviction),基于时间回收(Timed Eviction)和基于引用类型的回收(Reference-based Eviction)和手动回收。

基于容量回收(Size-based Eviction)

这种方式可以将缓存数据的数目限制在一个最大值一下,再缓存数据数据接近这个最大值时,Guava Cache 会按照LRU原则回收最近没有使用或者很少使用缓存数据,再开吗中可以通过 CacheBuilder.maximumSize(long) 方法进行设置,但在使用前,你最好预估一下的数据所占用的内存空间,达到最大值时是否有可能造成内存溢出。

基于时间回收(Timed Eviction)

Guava Cache 定义了两种基于时间的缓存回收方式:
CacheBuilder.expireAfterAccess(duration,unit):缓存项在给定时间内没有给访问过(包括读写操作)则会被回收,回收方式按照最近最少使用的原则。代码例如:CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES),表示缓存项在10分钟之内没有读写过,则会被回收。这种方式在实际项目场景中很有用,它可以确保在缓存条目有限的情况下,缓存中保留的都是最近经常使用的热点数据,从而提高缓存的整体命中率。
CacheBuilder.expireAfterWrite (duration, unit),另外一种方式是在缓存项在给定时间内没有被更新(包括创建和覆盖),则可以回收。

基于引用类型的回收(Reference-based Eviction)

Java语言中有强引用,弱引用和软引用的概念,强引用就是最常见的应用方式,被变量赋值就是强引用,只要引用关系存在,应用的对象就不会被垃圾回收。相比于强引用,使用弱引用关联的对象,只要系统进行垃圾回收,弱应用对象就会被回收,而软应用的强度介于弱引用和强引用之间,在内存空间不足,系统内存溢出之前,使用软引用关联的对象才会被回收。
CacheBuilder.weakKeys():按照弱引用的方式存储键值,当没有引用(强应用或者软引用)指向某键值时,允许系统在进行垃圾回收时回收缓存项。因为垃圾回收仅仅依赖于恒等式() 来比较对象(对象地址比较),该方法使得缓存在比较键值时用恒等式()比较,而不是 equals() 方法。
CacheBuilder.weakValues():和 CacheBuilder.weakKeys() 方法类似,该方法按照弱引用方式来存储缓存项的值,允许系统垃圾回收时回收缓存项。
CacheBuilder.weakValues(),使用软引用方式来包装缓存值,只有在内存需要时(一般在接近内存溢出时),系统会按照全局LRU(least-recently-used)原则进行垃圾回收。考虑到垃圾回收的性能问题,推荐使用基于容量的回收方式。
手动回收方式:

除了上述三种自动回收方式以外,还可以通过如下方法进行

手动缓存回收

  • 回收单个缓存项,Cache.invalidate(key)
  • 批量回收,Cache.invalidateAll(keys)
  • 全部回收Cache.invalidateAll()

​ 实际上,Guava Cache 并不会自动清理缓存,而是在写操作时捎带完成清理工作,如果写操作如果过少的花,也会在部分读操作中进行清理。Guava Cache 之所以不单独启一个线程来实现缓存的自动清理,是为了降低维护成本,避免和用户线程之间产生竞争,而且某些场景下,可能并不能随意创建线程。如果你不想让清理工作影响你的缓存的读写操作,你可以自行维护一个清理线程,周期性调用 cache.cleanUp() 方法定期清理。

运维监控缓存

​ 另外,Guava Cache 还提供了一些运维方法,帮助我们监控缓存运行状使用 CacheBuilder.recordStats()开启统计功能,cache.stats() 返回的 CacheStats 对象来查看运行的统计信息,可以监控好的信息有,主要的统计功能包括:

  • hitRate(), 缓存命中率。 hitCount(),缓存命中次数。
  • loadCount(),新值加载次数。
  • requestCount(),缓存访问次数,是命中次数和非命中次数之和
  • averageLoadPenalty(),加载新值时的平均耗时,以纳秒为单位。
  • evictionCount(),除了手动清除意外的缓存回收总次数。

除此之外,还有其他很多统计信息,这些信息可以有效帮助我们优化缓存的设置。

并发级别设置:
​ 类似于 ConcurrentHashMap 中的并发级别,Guava Cache 通过改值讲内部数据结构拆分成固定数量的段,缓存数据在段中存储,每个段有自己的写锁,段与段之间互不影响,所以并发级别越大,分的段越多,并发能力越强,如果你的服务QPS比较大的花,可以适当调大并发级别,用法如:

CacheBuilder.newBuilder().concurrencyLevel(20)

完整例子

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.stereotype.Component;


import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * {@linkplain Object}缓存。
 *
 * @author liuf *
 */
@Component
public class Cache
{
	/** 缓存值的最大数 */
	private int maximumSize = 1000;

	/** 缓存过期分钟数 */
	private int expireAfterAccessMinutes = 60 * 72;

	private  Cache<String,Object> _cache = null;

	public Cache()
	{
		super();
	}

	public int getMaximumSize()
	{
		return maximumSize;
	}

	public void setMaximumSize(int maximumSize)
	{
		this.maximumSize = maximumSize;
	}

	public int getExpireAfterAccessMinutes()
	{
		return expireAfterAccessMinutes;
	}

	public void setExpireAfterAccessMinutes(int expireAfterAccessMinutes)
	{
		this.expireAfterAccessMinutes = expireAfterAccessMinutes;
	}

	/**
	 * 初始化。
	 */
	@PostConstruct
	public void init() {
		_cache = CacheBuilder.newBuilder().maximumSize(this.maximumSize).expireAfterAccess(this.expireAfterAccessMinutes * 60, TimeUnit.SECONDS).build();
	}

	/**
	 * 获取{@linkplain Object}。
	 *
	 * @param schemaId
	 * @param tableName
	 * @return 返回{@code null}表示没有缓存
	 */
	public  Object get(String key)
	{
		return this._cache.getIfPresent(key);
	}

	/**
	 * 将{@linkplain Object}添加至缓存。
	 *
	 * @param key
	 * @param o
	 */
	public  void put(String key,Object o)
	{
		this._cache.put(key, o);
	}

	/**
	 * 清除指定名称{@linkplain Object}缓存。
	 *
	 * @param key
	 * @param Object
	 */
	public  void invalidate(String key)
	{
		this._cache.invalidate(key);
	}

	public static void main(String[] args) {
		Cache cache = new Cache();
		cache.init();
		Object map = new Object();
		map.setId("111111");
		cache.put("1",map);

		System.out.println(cache.get("1"));

	}```


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring boot 集成 Guava Cache 的相关文章

随机推荐

  • 说说家乡的互联网-江西龙南

    刚好在CSDN查资料 xff0c 看到这个征文 xff0c 勾起年少回忆 xff0c 遂写下此文 2003年 xff0c 我刚上初一 xff0c 学校开设了微机课 xff0c 我第一次接触了互联网 十一 xff0c 二岁的孩子对新事物充满了
  • 关于springmvc拦截器不拦截jsp页面

    一 xff0c 拦截器的用法 编写拦截器类 继承HandlerInterceptorAdapter类并重写需要的方法 或实现HandlerInterceptor接口并实现所有方法在spring mvc xml 也就是springmvc的配置
  • docker内部运行systemctl命令失败问题

    一般会提示以下错误 Failed to get D Bus connection Operation not permitted 网上好多解决方式都是说要在docker run的时候加 privileged参数 xff0c 但是本人经过测试
  • 在jupyter notebook导入tensorflow出错 - No module named tensorflow

    环境 xff1a win10 43 anaconda 问题 xff1a 在运行Jupyter Noterbook中import tensorflow报错 解决方法 xff1a 先按照这边文章Win10 Tensorflow2安装 xff0c
  • 手把手教你用Hexo+(Coding/GitHub)搭建个人博客及绑定私有域名

    Hexo是一个开源的静态博客框架 xff0c 支持markdown文档 xff0c 应用起来很方便而且有丰富的主题模板可供选择 xff0c 是建立个性化的个人博客的不二之选 以下以Coding 43 hexo为例搭建个人博客 因为GitHu
  • python 读写文件 删除文件

    概述 xff1a 主要内容 python read write 删除文件写 xff1b 在 39 w 39 和 39 a 39 模式下 xff0c 如果你打开的文件不存在 xff0c 那么open 函数会自动帮你创建一个 1 写入和读取文件
  • 看完微信抢红包算法你就明白,为啥你不是手气最佳

    摘要 xff1a 今天我们就来分析一下抢红包的算法 xff0c 其中有一些是微信红包的算法 xff0c 看完你就知道手气最佳是如何产生的啦 本文分享自华为云社区 为啥春节抢红包总不是手气最佳 xff1f 看完微信抢红包算法你就明白了 xff
  • python读音播报-基于python GUI开发的点名小程序(语音播报)

    实现名单轮播 点名 语音播报功能 coding utf8 ProjectName python3 FileName name Author shuxiaying Date 2020 7 9 Description import dateti
  • python编程100个小程序-整理了适合新手的20个Python练手小程序

    即刻关注公众号 xff0c 发现世界的美好 100个Python练手小程序 xff0c 学习python的很好的资料 xff0c 覆盖了python中的每一部分 xff0c 可以边学习边练习 xff0c 更容易掌握python 程序1 题目
  • python编程入门书籍-最适合Python初学者的6本书籍推荐「必须收藏」

    原标题 xff1a 最适合Python初学者的6本书籍推荐 必须收藏 Python是一种通用的解释型编程 xff0c 主要用于Web开发 机器学习和复杂数据分析 Python对初学者来说是一种完美的语言 xff0c 因为它易于学习和理解 x
  • dubbo好书推荐

    为了自己的进步 xff0c 也为了能够帮助其他人 xff0c 我决定开始写一些东西 xff0c 网上有很多学习资料 xff0c 自己的功力未必到家 xff0c 所以大家共同进步吧 xff01 站在巨人的肩膀上看得远 xff0c 现在推荐一本
  • linux升级java的jdk版本

    这里以升级jdk 8u231 linux x64 rpm为示例 安装 xff0c rpm ivh jdk 8u161 linux x64 rpmrpm pql root jdk 8u161 linux x64 rpm 通过查看 jdk 的信
  • you-get简明使用教程

    前言 近期 xff0c 想要下载哔哩哔哩等网站的视频 xff0c 网上查了一下you get的使用教程和视频 xff0c 有些特别简单 xff0c 说的不求甚解 xff0c 有些讲的太过繁琐 xff0c 所以 xff0c 打算自己写一个简单
  • linux分区扩容(非lvm)

    前言 最近 xff0c 在使用linux中中 xff0c 对于分区空间不够使用的情况下 xff0c 如果是使用lvm的分区 xff0c 是可以使用lvm扩容的 xff0c 流程大概是 xff1a 新加磁盘 将新加的磁盘创建成pv 将新加的p
  • linux关闭virbr0网卡

    前言 最近 xff0c 在使用linux时 要求需要关闭virbr0的网卡 xff0c 网上查了一下virbr0是kvm虚拟机使用的网卡 xff0c 是libvirtd服务安装后 xff0c 自动生成的 xff0c virbr0的配置文件位
  • rsync定时备份数据

    前言 rsync定时备份数据 简介 使用非系统用户备份数据192 168 130 63的 var www html 目录到192 168 130 64的 web bak目录 rsync定时备份数据 实验环境 xff1a 服务器 xff1a
  • rsync+sersync实时同步数据

    前言 rsync 43 sersync实时同步数据 简介 rsync 43 sersync实时同步数据的原理是在客户端安装sersync监控目录的变化 xff0c 一般是增删改 xff0c 检测到变化以后 xff0c 将变化的文件同步到服务
  • 配置 NFS 服务简述

    前言 配置 NFS 服务简述 简介 nfs utils服务依赖于rpcbind的服务 xff0c 是将服务端的目录共享 xff0c 其实是共享的 整个服务端的空间 xff0c 在客户端将共享目录挂载使用即可 配置 NFS 服务简述 实验环境
  • javaweb中四大域对象的生命周期与常用方法

    一 ServletContext 1 生命周期 xff1a 当Web应用被加载进容器时创建代表整个web应用的ServletContext对象 xff0c 当服务器关闭或Web应用被移除时 xff0c ServletContext对象跟着销
  • spring boot 集成 Guava Cache

    Guava Cache 背景集成缓存存放缓存回收 xff1a 基于容量回收 xff08 Size based Eviction xff09 基于时间回收 xff08 Timed Eviction xff09 基于引用类型的回收 xff08