1. Caffeine 簡介
Caffeine 是一個基于 Java 8 的高性能本地緩存庫,由 Ben Manes 開發,旨在替代 Google Guava Cache,提供更優的緩存策略、更高的吞吐量和更靈活的配置。
核心優勢
? 卓越的性能:采用優化的數據結構(如 Window TinyLFU 淘汰算法),減少鎖競爭,提升并發訪問效率。
? 靈活的緩存策略:支持基于大小、時間、權重等多種淘汰機制。
? 豐富的功能:自動刷新、異步加載、批量操作等高級特性。
? 無縫集成 Spring:與 Spring Cache 完美結合,輕松替換 Redis 或 Ehcache。
2. Caffeine 核心機制
2.1 緩存淘汰策略
Caffeine 提供多種緩存淘汰策略,防止內存無限增長:
策略 | 方法 | 說明 |
---|---|---|
基于大小 | maximumSize(long) | 限制緩存最大條目數 |
基于權重 | maximumWeight(long) + weigher() | 根據條目權重限制緩存 |
基于時間 | expireAfterWrite / expireAfterAccess | 寫入/訪問后過期 |
手動淘汰 | invalidate(key) / invalidateAll() | 主動移除緩存 |
2.2 緩存加載方式
Caffeine 支持 同步加載 和 異步加載:
// 同步加載(阻塞)
LoadingCache<Key, Value> cache = Caffeine.newBuilder().build(key -> fetchFromDB(key));// 異步加載(非阻塞)
AsyncLoadingCache<Key, Value> asyncCache = Caffeine.newBuilder().buildAsync((key, executor) -> CompletableFuture.supplyAsync(() -> fetchFromDB(key), executor));
2.3 自動刷新機制
refreshAfterWrite
允許緩存條目在寫入后一段時間自動刷新(異步,不阻塞請求):
LoadingCache<String, Data> cache = Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.MINUTES) // 1分鐘后訪問時觸發刷新.build(this::loadDataFromDB);
注意:刷新時返回舊值,后臺異步加載新值,適合高并發場景。
3. 代碼實戰:Caffeine + Spring Boot
3.1 基礎配置
@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic Caffeine<Object, Object> caffeineConfig() {return Caffeine.newBuilder().maximumSize(1000) // 最大1000條.expireAfterWrite(10, TimeUnit.MINUTES) // 10分鐘過期.refreshAfterWrite(1, TimeUnit.MINUTES); // 1分鐘后自動刷新}@Beanpublic CacheManager cacheManager(Caffeine<Object, Object> caffeine) {CaffeineCacheManager cacheManager = new CaffeineCacheManager();cacheManager.setCaffeine(caffeine);return cacheManager;}
}
3.2 業務層使用
@Service
public class UserService {@Cacheable(value = "users", key = "#id") // 緩存名稱為 "users"public User getUserById(Long id) {return userRepository.findById(id).orElse(null);}@CacheEvict(value = "users", key = "#id") // 刪除緩存public void deleteUser(Long id) {userRepository.deleteById(id);}
}
4. 高級用法
4.1 多級緩存(Caffeine + Redis)
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,Caffeine<Object, Object> caffeine
) {// 本地緩存CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();caffeineCacheManager.setCaffeine(caffeine);// Redis 緩存RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()).build();// 組合緩存(先查本地,再查Redis)return new CompositeCacheManager(caffeineCacheManager, redisCacheManager);
}
4.2 批量操作優化
public Map<Long, User> batchGetUsers(List<Long> userIds) {// 批量查詢緩存Map<Long, User> cachedUsers = cache.getAll(userIds);// 查找未命中的IDList<Long> missingIds = userIds.stream().filter(id -> !cachedUsers.containsKey(id)).collect(Collectors.toList());if (!missingIds.isEmpty()) {// 從DB加載并更新緩存Map<Long, User> dbUsers = userRepository.batchFindByIds(missingIds);cache.putAll(dbUsers);cachedUsers.putAll(dbUsers);}return cachedUsers;
}
5. 注意事項 & 最佳實踐
5.1 緩存穿透問題
問題:惡意請求不存在的 key,導致頻繁查詢數據庫。
解決方案:
.build(key -> {User user = fetchFromDB(key);if (user == null) {return new NullValue(); // 緩存空對象}return user;
});
5.2 緩存雪崩
問題:大量緩存同時失效,導致數據庫壓力激增。
解決方案:
.expireAfterWrite(10 + ThreadLocalRandom.current().nextInt(5), TimeUnit.MINUTES) // 隨機過期時間
5.3 內存監控
Caffeine 提供統計信息:
.recordStats() // 啟用統計
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());
System.out.println("加載次數: " + stats.loadCount());
5.4 最佳實踐
? 合理設置緩存大小:避免 OOM(如 maximumSize(10000)
)。
? 結合 TTL + 自動刷新:保證數據新鮮,同時避免阻塞請求。
? 分布式環境使用多級緩存:本地緩存 + Redis,減少網絡開銷。
? 監控緩存命中率:優化緩存策略,避免緩存失效風暴。
6. 總結
Caffeine 是 Java 生態中最強大的本地緩存庫之一,適用于:
- 高頻訪問的只讀數據(如配置、用戶信息)
- 高并發場景(如電商商品詳情頁)
- 計算成本高的操作(如復雜查詢、API 調用)
通過合理的配置(refreshAfterWrite
+ expireAfterWrite
)和最佳實踐(防穿透、防雪崩),可以極大提升系統性能。
推薦組合:
- 單機應用:純 Caffeine
- 分布式系統:Caffeine + Redis(多級緩存)
附錄:官方資源
- GitHub: Caffeine
- Spring Cache + Caffeine
希望這篇深度解析能幫助你掌握 Caffeine 的核心機制和最佳實踐! 🚀