跟着 Guava 学 Java 之缓存

本文介绍了缓存的基本概念、特点和应用场景,特别讲解了Java中Guava Cache的使用,包括加载、缓存回收机制、移除监听器、统计信息以及与Caffeine的对比。Guava Cache提供了丰富的配置选项和高性能的本地缓存解决方案,适用于提高系统响应速度和减轻数据库压力。
摘要由CSDN通过智能技术生成

本文我们先介绍一些缓存的背景知识,以及内存缓存的流行开源库类实现,最后利用一些例子重点介绍下 Guava Cache 的缓存功能。

背景

什么是缓存

在计算中,缓存是一个高速数据存储层,其中存储了数据子集,且通常是短暂性存储,这样日后再次请求该数据时,速度要比访问数据的主存储位置快。通过缓存,可以高效地重用之前检索或计算的数据。

本文中所提及的缓存主要是指内存缓存,跟硬件没什么关系(比如三级缓存什么的),主要是应用代码层面和内存交互的这部分。

缓存的特点

第一个特点:贼快(操作内存读写当然快了)

你可能会问了,贼快是多快?嗯,没有对比就没有伤害,我们来看一下不同介质访问数据的时间情况

看到了吧,RAM 的速度大概是 10-100 纳秒,什么概念? 1 秒钟等于 10 亿纳秒,这速度快到你根本感觉不到。

第二个特点:说没就没

  • 断电立即丢失
  • 超过缓存失效时间

解决什么问题

一般来说,我们利用本地的内存缓存主要可以达到减轻数据库压力、提高系统响应速度和吞吐量的目的。

总之,如果对某些值的计算或检索成本很高,并且多次需要使用该值时,应该考虑使用缓存。

内存缓存库类

在 Java 中一提到缓存,我们首先想到的可以用 ConcurrentHashMap做缓存。

static ConcurrentHashMap<String,Object> localCache = new ConcurrentHashMap<>();

为什么要用 ConcurrentHashMap 呢?

因为首先它是个 Map,这种 K,V 的数据结构很适合用来读写缓存对象,其次它还是线程安全的,多线程并发不会有线程安全问题。

Java 虽然为我们提供了ConcurrentHashMap 这样合适做缓存的数据结构,但他在功能上却有很多的不足,比如没有 回收、驱逐、监听、刷新等功能。一般来说,我们设计一套完整的缓存方案虽然这些功能,用 ConcurrentHashMap意味着这些功能你要自己开发了。

在 Java 的生态中有许多库可以帮助我们省去自己开发的麻烦,人家都封装好了,开箱即用,这里我们列举几个知名和常用的,后面我们重点介绍 Guava 的 cache 模块:

  • Guava Cache
  • Spring Cache Spring 提供的一整套的缓存解决方案。虽然它本身并没有提供缓存的实现,但是它提供了一整套的接口和代码规范、配置、注解等,这样它就可以整合各种缓存方案了,比如 Redis、Ehcache,我们也就不用关心操作缓存的细节。
  • Caffeine(以 GuavaCache 为原型而开发的一个本地缓存框架,相对 GuavaCache, 它有更高的性能与命中率,更强大的功能,更灵活的配置方式)
  • J2Cache(OSChina 开源的一个两级缓存框架,采用固定的 一级 + 二级缓存 的模式,从一开始就是为了解决两级缓存一致性的问题)
  • JetCache(是阿里开源的通用缓存访问框架,它统一了多级缓存的访问方式,封装了类似于 SpringCache 的注解,以及 GuavaCache 类似的 Builder, 来简化项目中使用缓存的难度)

这里多说两句:

Caffeine是当前最优秀的内存缓存框架,不论读还是写的效率都远高于其他缓存,而且在Spring5开始的默认缓存实现就将 Caffeine 代替原来的 Guava。

在项目中,比如你用 SpringBoot 想加本地缓存,我们通常会引入 SpringCache+Caffeine的依赖。使用 SpringCache 注解方法实现缓存。SpringCache 帮我们封装了 Caffeine,通过这种方式集成 Caffeine。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

有朋友说了,你这是一级缓存,我们一般会使用二级缓存,即一级缓存用 caffeine 二级缓存用 Redis(强强联合,很常用的方案),一级缓存找不到去二级缓存找。

没错,如果你想用 SpringBoot 集成 CaffeineRedis实现二级缓存,有两种方式:

第一种,直接集成,引入的依赖有变化:


  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
  </dependency>
  <dependency>
      <groupId>com.github.ben-manes.caffeine</groupId>
      <artifactId>caffeine</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>

这里顺便说一下 spring-boot-starter-data-redis ,spring-data-redis 和 Redis 的关系如下图,延续了 Spring 的一贯思想,对上层仍然是一层封装,对底层支持各种 Redis 客户端的实现。

第一种方式的集成比较简单,但请注意 spring cache (caffeine) 和 spring-data-redis(redis),是各管各的(如前面括号里写的),不好意思,一二级缓存之间的逻辑关系需要你自己处理 具体来说比如你可以实现 cache 拦截器 CacheInterceptor

这里有一个比较容易混乱的点, spring cache 是支持多个 Provider 的:

  1. Generic
  2. JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
  3. EhCache 2.x
  4. Hazelcast
  5. Infinispan
  6. Couchbase
  7. Redis
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值