Redis 这种 NoSql 作为缓存组件,它能够很好的作为分布式缓存组件提供多个服务间的缓存,但是 Redis 这种还是需要网络开销,增加时耗。本地缓存是直接从本地内存中读取,没有网络开销,例如秒杀系统或者数据量小的缓存等,比远程缓存更合适.
Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。
<!-- 一级缓存,效率:caffeine > guava > redis -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.0</version>
</dependency>
配置类
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
public class Caffeine {
@Bean
public Cache<String, Object> caffeineCache() {
return com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
// 设置每个key的过期时间
.expireAfterWrite(60, TimeUnit.SECONDS)
// 初始的缓存空间大小(键值对的数量,而不是内存大小)
.initialCapacity(100)
// 缓存的最大条数
.maximumSize(1000)
.build();
}
}
工具类
import com.github.benmanes.caffeine.cache.Cache;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
@Component
public class CaffeineUtils<T> {
@Resource
Cache<String, Object> caffeineCache;
// 添加缓存
public void put(String key, Object value){
// 添加一级缓存
caffeineCache.put(key,value);
}
// 获取数据
public T get(String key){
T info = (T) caffeineCache.asMap().get(key);
return info;
}
// 判断缓存是否存在
public boolean exist(String key){
Object ifPresent = caffeineCache.getIfPresent(key);
// 非空 true
return !ObjectUtils.isEmpty(ifPresent);
}
// 移除数据
public void remove(String key){
caffeineCache.asMap().remove(key);
}
}
使用
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class FirstCacheController {
@Resource
CaffeineUtils firstAndSecondCache;
@Resource
private RedisTemplate<String, Object> redisTemplate;
// 添加缓存
@RequestMapping("addCache")
public void addFirstCache(String key){
Map<String,Object> map = new HashMap<>();
map.put("a","1");
// 一级缓存
firstAndSecondCache.put(key,map);
// 二级缓存
redisTemplate.opsForHash().putAll(key, map);
}
// 缓存是否存在
@RequestMapping("existFirstCache")
public void existFirstCache(String key){
System.out.println(firstAndSecondCache.exist(key));
}
// 获取缓存数据
@RequestMapping("getFirstCache")
public Object getFirstCache(String key){
Object o;
//1. 一级缓存存在,返回数据
if(firstAndSecondCache.exist(key)){
o = firstAndSecondCache.get(key);
return o;
}
//2. 一级缓存不存在,判断二级缓存是否存在
if(redisTemplate.hasKey(key)){
// 二级缓存数据存在
o = redisTemplate.opsForHash().entries(key);
// 将二级缓存数据同步给一级缓存
firstAndSecondCache.put(key,o);
return o;
}
//3. 一级缓存不存在,二级缓存也不存在
//3.1 数据源 Mysql 中取数据 ,此处模拟。
if(true){
Map<String,Object> map = new HashMap<>();
map.put("a",2);
o = map;
//3.2 将数据缓到 二级缓存 AND 一级缓存
redisTemplate.opsForHash().putAll(key, map);
firstAndSecondCache.put(key,map);
}
return o;
}
//移除缓存
@RequestMapping("deleteFirstCache")
public void deleteFirstCache(String key){
firstAndSecondCache.remove(key);
redisTemplate.delete(key);
}
}