跳至主要内容

快取模組

AppFuse Server 提供基於分層架構 + 適配器模式的快取工具集。

核心特色

1. 介面導向設計

底層可從 Ehcache 切換到 Caffeine/Redis,應用程式碼無需修改。

2. 管理功能

  • 停用/啟用: 系統維護時暫時停用快取
  • 層級清除: 精確控制清除範圍
  • 狀態查詢: 即時監控命中率、容量使用

3. 雙層快取架構 (DualLayerCache)

  • 快速層: 短期熱資料,可過期
  • 持久層: 長期全量資料,永不過期
  • 自動降級: 快速層 miss 時自動查詢持久層

標準快取

基本用法

import io.leandev.appfuse.cache.*;

// 建立快取
Cache<String, User> userCache = CacheBuilder
.newCache(cacheManager, "users", String.class, User.class)
.heap(100) // 堆內 100 條
.offheap(20) // 堆外 20MB
.ttl(30) // 30 分鐘過期
.build();

// 使用快取
userCache.put("user1", user);
User user = userCache.get("user1");
userCache.remove("user1");

Cache-Aside Pattern

public Optional<User> findById(String id) {
// 1. 先查快取
User cached = userCache.get(id);
if (cached != null) {
return Optional.of(cached);
}

// 2. 快取未命中,查資料庫
return userRepository.findById(id)
.map(user -> {
// 3. 寫入快取
userCache.put(id, user);
return user;
});
}

雙層快取

適用於需要容錯的場景,如 Session 管理。

import io.leandev.appfuse.cache.*;

// 建立雙層快取
DualLayerCache<String, Session> sessionCache = DualCacheBuilder
.newCache(cacheManager, "sessions", String.class, Session.class)
.fastHeap(100) // 快速層:堆內 100 條
.fastOffheap(10) // 快速層:堆外 10MB
.fastTtl(30) // 快速層:30 分鐘過期
.store(200) // 持久層:200 條
.build();

// 自動降級:快速層 miss 時自動查詢持久層
String userId = sessionCache.get(sessionId);

// 不降級模式
String userId = sessionCache.get(sessionId, false);

雙層快取架構圖

快取啟用開關

CacheManager 提供管理器層級的啟用/停用開關(ADR-007),主要供除錯/測試「強制讀資料源」。停用語意為邏輯旁路、不清空資料——停用期間 get 強制 miss、put 被忽略,底層資料保留,重新啟用即可再服務。

管理器層總閘

disableAll() 一次停用此管理器下所有 managed 快取;enableAll() 翻回總閘。停用後新建立(含懶建)的 managed 快取也自動受總閘管制;enableAll() 僅翻回總閘,不會覆蓋個別快取以 disableCache() 設定的停用狀態。

cacheManager.disableAll(); // 全部停用:每次 get 都 miss、強制讀資料源
cacheManager.enableAll(); // 恢復服務
boolean on = cacheManager.isEnabled(); // 查詢總閘狀態

個別快取開關

disableCache(name) / enableCache(name) 停用/啟用單一快取,與總閘正交——即使總閘啟用,被指名的快取仍停用。可在快取建立之前先指名,之後懶建的同名快取會以停用狀態誕生。有效服務狀態為兩層 AND:總閘 isEnabled() AND 個別開關。

cacheManager.disableCache("users"); // 只停用 users 快取
boolean served = cacheManager.isCacheEnabled("users"); // 總閘 AND 個別開關

停用 ≠ 清空:停用是旁路、不動底層資料;如需新鮮資料另以 clear() 處理。

Property 接線由消費端承擔

框架只提供 disableAll() / disableCache()介面原語,不出貨 @AutoConfiguration / @ConfigurationProperties。將設定(如 app.cache.enabled / app.cache.disabled-caches)接到原語呼叫,是消費端的責任——參考實作的 CacheConfig 示範了這段接線:

// 參考實作 CacheConfig(消費端):讀設定→呼叫原語
if (!cacheEnabled) { // app.cache.enabled=false
cacheManager.disableAll();
} else {
disabledCaches.forEach(cacheManager::disableCache); // app.cache.disabled-caches=users,rateLimit
}

此接線在 CacheManager 建立時即套用,故即使各快取 bean 稍後才建立(DI 順序在後或懶建)仍正確受管。詳見 ADR-007: 快取啟用開關

快取模式比較

模式適用場景範例
Cache-Aside使用者資訊、產品資料UserCacheService
Write-Through需要強一致性的場景訂單狀態
Time-to-IdleAPI 限流、防爆破RateLimitService

詳細 API

請參閱 Cache API 參考Javadoc