1. 概述
Caffeine 是目前 Java 领域性能最强的本地缓存库之一,基于 Java 8 构建,集成了最佳实践的缓存策略(如 W-TinyLFU),在命中率和吞吐量上都显著优于传统的 Guava Cache。
本文将介绍如何在 Spring Boot 项目中集成 Caffeine,实现高效的方法级缓存。✅
2. 依赖配置
要使用 Caffeine + Spring Boot 的缓存能力,需引入两个核心依赖:
spring-boot-starter-cache
:Spring Boot 提供的缓存抽象启动器caffeine
:Caffeine 缓存库本身
Maven 配置如下:
<dependencies>
<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>
</dependencies>
⚠️ 注意:无需手动引入 spring-context
或 cache-api
,这些已被 starter 自动包含。
3. 缓存配置
Spring 的缓存机制是基于抽象的,要使用 Caffeine,需提供两个核心 Bean:
3.1 配置 Caffeine 实例
通过 @Bean
定义一个 Caffeine
实例,用于设置缓存行为,例如:
- 写入后过期时间
- 最大缓存条目数
- 是否开启统计(用于监控)
@Bean
public Caffeine caffeineConfig() {
return Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.maximumSize(500)
.recordStats(); // 启用统计
}
✅ recordStats()
是调试和监控的关键,开启后可通过 Cache.stats()
获取命中率、请求总数等指标。
3.2 配置 CacheManager
Spring 通过 CacheManager
管理缓存实例。Caffeine 提供了 CaffeineCacheManager
实现类:
@Bean
public CacheManager cacheManager(Caffeine caffeine) {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(caffeine);
return cacheManager;
}
⚠️ 注意:CaffeineCacheManager
默认会为每一个 @Cacheable
中的 value
创建一个独立缓存实例,无需额外配置。
3.3 启用缓存支持
在任意 @Configuration
类上添加 @EnableCaching
注解,开启 Spring 的缓存功能:
@Configuration
@EnableCaching
public class CacheConfig {
// 配置 Bean 方法...
}
✅ 这一步是必须的,否则 @Cacheable
等注解不会生效。
4. 使用示例
配置完成后,即可在服务中使用缓存注解。
4.1 基础用法:@Cacheable
最常见的方式是在服务方法上使用 @Cacheable
,自动缓存方法返回值。
@Service
public class AddressService {
@Cacheable("address_cache")
public AddressDTO getAddress(long customerId) {
System.out.println("查询数据库: " + customerId);
// 模拟 DB 查询
return new AddressDTO("北京市朝阳区", "100001");
}
}
✅ 第一次调用会执行方法体并缓存结果,后续相同参数调用将直接从缓存返回,不再执行方法。
4.2 自定义缓存名与键
默认情况下:
- 缓存名:使用类名 + 方法名
- 缓存键:方法参数(若只有一个参数,则直接用该参数值)
可通过注解参数显式指定:
@Service
public class AddressService {
@Cacheable(value = "address_cache", key = "#customerId")
public AddressDTO getAddress(long customerId) {
System.out.println("查询数据库: " + customerId);
return new AddressDTO("北京市朝阳区", "100001");
}
}
value
:指定缓存名称,对应CaffeineCacheManager
中的缓存实例key
:使用 SpEL 表达式定义缓存键 ❗
✅ 推荐始终显式指定 value
,避免命名冲突和后期维护困难。
4.3 多参数方法的缓存键
当方法有多个参数时,需明确指定 key,否则可能因参数顺序或类型导致缓存错乱:
@Cacheable(value = "user_order", key = "#userId + '_' + #orderId")
public OrderDTO getOrder(long userId, long orderId) {
// 查询逻辑
}
✅ 使用 SpEL 拼接复合键是常见做法,清晰且可控。
4.4 手动操作缓存
除了注解方式,也可直接注入 CacheManager
进行编程式缓存操作:
@Service
public class AddressService {
@Autowired
private CacheManager cacheManager;
public AddressDTO getAddress(long customerId) {
Cache cache = cacheManager.getCache("address_cache");
// 先尝试从缓存获取
Cache.ValueWrapper wrapper = cache.get(customerId);
if (wrapper != null) {
return (AddressDTO) wrapper.get();
}
// 缓存未命中,查数据库
AddressDTO address = queryFromDB(customerId);
cache.put(customerId, address); // 手动放入缓存
return address;
}
private AddressDTO queryFromDB(long customerId) {
System.out.println("查询数据库: " + customerId);
return new AddressDTO("北京市朝阳区", "100001");
}
}
⚠️ 手动方式更灵活,但需注意缓存一致性,建议仅在复杂场景下使用。
5. 结论
通过本文,我们完成了:
- ✅ 引入 Caffeine 依赖
- ✅ 配置
Caffeine
和CaffeineCacheManager
Bean - ✅ 使用
@EnableCaching
启用缓存 - ✅ 实践
@Cacheable
注解和手动缓存操作
Caffeine + Spring Boot 的组合简单粗暴,性能拉满,是本地缓存的首选方案。尤其适合高频读、低频写的场景,比如配置缓存、用户信息缓存等。
所有示例代码已托管至 GitHub:
👉 https://github.com/eugenp/tutorials/tree/master/spring-boot-modules/spring-boot-libraries
踩坑提醒:
❌ 忘记加 @EnableCaching
—— 注解不生效
❌ 缓存 key 冲突 —— 多方法共用同一缓存名时未区分 key
✅ 建议结合 Micrometer + Prometheus 监控缓存命中率,及时发现问题。