一、Caffeine 缓存背景
Caffeine是一个高性能、可扩展的Java缓存库,由Google的Ben Manes开发。Caffeine基于ConcurrentHashMap设计,采用了近似LRU(Least Recently Used,最近最少使用)算法,以实现高速缓存淘汰策略。Caffeine广泛应用于各类Java项目中,作为一种提高数据读取性能的优秀解决方案。
二、Caffeine 缓存优点与缺点
优点:
高性能:Caffeine性能优于许多其他缓存库,因其采用了近似LRU算法,实现了高效的缓存淘汰策略。
灵活性:Caffeine提供了丰富的配置选项,用户可根据项目需求灵活定制缓存策略。
易集成:Caffeine可轻松与Spring Boot框架集成,实现便捷的缓存管理。
易于使用:Caffeine API简洁易懂,便于开发者快速上手。
缺点:
仅支持Java:Caffeine为Java特有的缓存库,不能直接应用于其他编程语言。
近似LRU算法:虽然Caffeine采用了高效的近似LRU算法,但在某些场景下,其性能可能不如精确的LRU算法。
三、Caffeine 缓存基本使用方法
1.添加Caffeine依赖:
<!-- caffeine服务器本地缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- caffeine -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.9.1</version>
</dependency>
<!-- 可以对自定义配置的信息进行提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
2.配置yml:
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=500,expireAfterWrite=10m
3.自定义缓存:MyCacheComponent.java(一般我都是用自定义的)
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.stereotype.Component;
import java.io.*;
@Component
public class MyCacheComponent {
private final Cache<String, byte[]> cache;
public MyCacheComponent() {
// 初始化Caffeine缓存,存储键为String类型,值为byte[]类型(序列化后的对象)
this.cache = Caffeine.newBuilder()
.maximumSize(100) // 设置缓存的最大容量
.build();
}
public void put(String key, Serializable value) {
try {
// 将对象序列化为字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(value);
byte[] serializedValue = byteArrayOutputStream.toByteArray();
// 将序列化后的字节数组存储到缓存中
cache.put(key, serializedValue);
} catch (IOException e) {
// 处理序列化时的异常
throw new RuntimeException("Failed to serialize value", e);
}
}
public <T extends Serializable> T get(String key, Class<T> type) {
byte[] serializedValue = cache.getIfPresent(key);
if (serializedValue != null) {
try {
// 将字节数组反序列化为对象
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(serializedValue));
return (T) objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
// 处理反序列化时的异常
throw new RuntimeException("Failed to deserialize value", e);
}
}
return null;
}
public <T extends Serializable> T get(String key) {
byte[] serializedValue = cache.getIfPresent(key);
if (serializedValue != null) {
try {
// 将字节数组反序列化为对象
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(serializedValue));
return (T) objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
// 处理反序列化时的异常
throw new RuntimeException("Failed to deserialize value", e);
}
}
return null;
}
public void delete(String key) {
byte[] serializedValue = cache.getIfPresent(key);
if (serializedValue != null) {
try {
cache.invalidate(key);
} catch (Exception e) {
throw new RuntimeException("Failed", e);
}
}
}
}
4.Impl中使用
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import xx.xxxx.xxx.utils.MyCacheComponent;
@Service
public class BaseServiceImpl implements BaseService {
@Autowired
private CacheManager cacheManager;
@Autowired
private MyCacheComponent myCacheComponent;
@Autowired
private BaseMapper baseMapper;
//新增业务
@Override
@Transactional(rollbackFor = Exception.class)
public void save(BaseDTO dto) {
if (dto.getUserId != null) {
//新增前先删除缓存
myCacheComponent.delete(userId);
}
···
···
//执行新增操作
baseMapper.insert(entity);
//新增完删除缓存,避免并发导致脏数据
if (dto.getUserId != null) {
//新增完删除缓存
myCacheComponent.delete(userId);
}
}
//修改业务
@Override
@Transactional(rollbackFor = Exception.class)
public void update(BaseDTO dto) {
if (dto.getUserId != null) {
//修改前先删除缓存
myCacheComponent.delete(userId);
}
···
···
//执行修改操作
baseMapper.updateById(entity);
//修改完删除缓存,避免并发导致脏数据
if (dto.getUserId != null) {
//修改完删除缓存
myCacheComponent.delete(userId);
}
}
//获取数据
@Override
public List<BaseVO> getList(Long userId) {
//查缓存,有则返回,没有则查询数据库,然后存进缓存
Object list = myCacheComponent.get(userId);
if(list != null){
return (List<BaseVO>) list;
}
···
···
//获取数据库或者redis数据
List<BaseEntity> dalist = baseMapper.selectList(Wrappers.<BaseEntity>);
//存入缓存
if (CollectionUtil.isNotEmpty(dalist)) {
myCacheComponent.put(userId, (Serializable) list);
}
}
}