Caffeine提供了三种定时驱逐策略:
expireAfterAccess(long, TimeUnit):在最后一次访问或者写入后开始计时,在指定的时间后过期。假如一直有请求访问该key,那么这个缓存将一直不会过期。
expireAfterWrite(long, TimeUnit): 在最后一次写入缓存后开始计时,在指定的时间后过期。expireAfter(Expiry): 自定义策略,过期时间由Expiry实现独自计算。缓存的删除策略使用的是惰性删除和定时删除。这两个删除策略的时间复杂度都是O(1)。
3. 基于引用的过期方式
Java中四种引用类型
引用类型 | 被垃圾回收时间 | 用途 | 生存时间 |
强引用 Strong Reference | 从来不会 | 对象的一般状态 | JVM停止运行时终止 |
软引用 Soft Reference | 在内存不足时 | 对象缓存 | 内存不足时终止 |
弱引用 Weak Reference | 在垃圾回收时 | 对象缓存 | gc运行后终止 |
虚引用 Phantom Reference | 从来不会 | 可以用虚引用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知 | JVM停止运行时终止 |
// 当key和value都没有引用时驱逐缓存 LoadingCache<String, Object> cache = Caffeine.newBuilder() .weakKeys() .weakValues() .build(key -> function(key)); // 当垃圾收集器需要释放内存时驱逐 LoadingCache<String, Object> cache1 = Caffeine.newBuilder() .softValues() .build(key -> function(key));
注意:AsyncLoadingCache不支持弱引用和软引用。
Caffeine.weakKeys():使用弱引用存储key。如果没有其他地方对该key有强引用,那么该缓存就会被垃圾回收器回收。由于垃圾回收器只依赖于身份(identity)相等,因此这会导致整个缓存使用身份 (==) 相等来比较 key,而不是使用 equals()。
Caffeine.weakValues() :使用弱引用存储value。如果没有其他地方对该value有强引用,那么该缓存就会被垃圾回收器回收。由于垃圾回收器只依赖于身份(identity)相等,因此这会导致整个缓存使用身份 (==) 相等来比较 key,而不是使用 equals()。
Caffeine.softValues() :使用软引用存储value。当内存满了过后,软引用的对象以将使用最近最少使用(least-recently-used ) 的方式进行垃圾回收。由于使用软引用是需要等到内存满了才进行回收,所以我们通常建议给缓存配置一个使用内存的最大值。softValues() 将使用身份相等(identity) (==) 而不是equals() 来比较值。
Caffeine.weakValues()和Caffeine.softValues()不可以一起使用。
3. 移除事件监听
Cache<String, Object> cache = Caffeine.newBuilder() .removalListener((String key, Object value, RemovalCause cause) -> System.out.printf("Key %s was removed (%s)%n", key, cause)) .build();
4. 写入外部存储
CacheWriter 方法可以将缓存中所有的数据写入到第三方。
LoadingCache<String, Object> cache2 = Caffeine.newBuilder() .writer(new CacheWriter<String, Object>() { @Override public void write(String key, Object value) { // 写入到外部存储 } @Override public void delete(String key, Object value, RemovalCause cause) { // 删除外部存储 } }) .build(key -> function(key));
如果你有多级缓存的情况下,这个方法还是很实用。
注意:CacheWriter不能与弱键或AsyncLoadingCache一起使用。
5. 统计
与Guava Cache的统计一样。
Cache<String, Object> cache = Caffeine.newBuilder() .maximumSize(10_000) .recordStats() .build();
通过使用Caffeine.recordStats(), 可以转化成一个统计的集合. 通过 Cache.stats() 返回一个CacheStats。CacheStats提供以下统计方法:
hitRate(): 返回缓存命中率 evictionCount(): 缓存回收数量 averageLoadPenalty(): 加载新值的平均时间
3. SpringBoot 中默认Cache-Caffine Cache
SpringBoot 1.x版本中的默认本地cache是Guava Cache。在2.x(Spring Boot 2.0(spring 5) )版本中已经用Caffine Cache取代了Guava Cache。毕竟有了更优的缓存淘汰策略。
下面我们来说在SpringBoot2.x版本中如何使用cache。
1. 引入依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.6.2</version> </dependency>
2. 添加注解开启缓存支持
添加@EnableCaching注解:
@SpringBootApplication @EnableCaching public class SingleDatabaseApplication { public static void main(String[] args) { SpringApplication.run(SingleDatabaseApplication.class, args); } }
3. 配置文件的方式注入相关参数
properties文件
spring.cache.cache-names=cache1 spring.cache.caffeine.spec=initialCapacity=50,maximumSize=500,expireAfterWrite=10s
或Yaml文件
spring: cache: type: caffeine cache-names: - userCache caffeine: spec: maximumSize=1024,refreshAfterWrite=60s
如果使用refreshAfterWrite配置,必须指定一个CacheLoader.不用该配置则无需这个bean,如上所述,该CacheLoader将关联被该缓存管理器管理的所有缓存,所以必须定义为CacheLoader<Object, Object>,自动配置将忽略所有泛型类型。
import com.github.benmanes.caffeine.cache.CacheLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author: rickiyang * @date: 2019/6/15 * @description: */ @Configuration public class CacheConfig { /** * 相当于在构建LoadingCache对象的时候 build()方法中指定过期之后的加载策略方法 * 必须要指定这个Bean,refreshAfterWrite=60s属性才生效 * @return */ @Bean public CacheLoader<String, Object> cacheLoader() { CacheLoader<String, Object> cacheLoader = new CacheLoader<String, Object>() { @Override public Object load(String key) throws Exception { return null; } // 重写这个方法将oldValue值返回回去,进而刷新缓存 @Override public Object reload(String key, Object oldValue) throws Exception { return oldValue; } }; return cacheLoader; } }
Caffeine常用配置说明:
initialCapacity=[integer]: 初始的缓存空间大小 maximumSize=[long]: 缓存的最大条数 maximumWeight=[long]: 缓存的最大权重 expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期 expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期 refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存 weakKeys: 打开key的弱引用 weakValues:打开value的弱引用 softValues:打开value的软引用 recordStats:开发统计功能 注意: expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准。 maximumSize和maximumWeight不可以同时使用 weakValues和softValues不可以同时使用