快取使用範例
cache Feature 只組裝共用 CacheManager;它不預建「使用者、session、驗證碼」等
假設產品一定需要的 cache。每個用途 cache 由真正的擁有 Feature 或業務域宣告,因此移除
optional Feature 時不會留下孤兒 bean。
共用 CacheManager
預設組裝位於 feature/cache/CacheConfig,並由 CacheProperties 接收少量環境差異:
app:
cache:
enabled: true
disabled-caches: []
# path: /srv/my-app/var/cache
# offheap-budget-mb: 512
path 省略時依序使用 ${app.home}/var/cache、${user.home}/var/cache;app.home 是
應用資料的正常位置,user.home 只是 fallback。offheap-budget-mb 省略時由 framework
依 container/JVM/host memory 自動推導;512 只應是部署明確決定的 override,不是
reference default。
enabled: false 是啟動 hard-disable:不解析/建立 path、不初始化 Ehcache,也不計算
offheap budget。disabled-caches 則是可恢復的 soft bypass。
以上皆有 production-safe 預設。只有需要 hard-disable、soft bypass、調整磁碟位置或固定
記憶體預算時才需覆寫。
server-tenant 與 server-tenantless 可使用相同 cache 能力;cache key 是否含租戶或 owner
是各模組與資料用途的責任,不由 runtime isolation 設定切換。
由擁有 Feature 宣告用途 cache
例如 auth 擁有登入失敗與 token blacklist:
@Bean
Cache<String, AttemptRecord> attemptCache(CacheManager manager) {
return CacheBuilder
.newCache(manager, "loginAttempts", String.class, AttemptRecord.class)
.heap(10_000)
.tti(Duration.ofMinutes(30))
.build();
}
signed-link 的 redemption cache 會自動以設定的最長 SINGLE_USE TTL 建立;service-account
則建立自己的 TTI 計數 cache,再交給框架的 CacheClientCredentialsRateLimiter。這些預設
都住 Feature,reference implementation 不需要重複一份接線碼。
業務 Cache-Aside
業務資料是否值得 cache、失效時機與 key 形狀是產品決策,應留在業務域:
public Product find(String id) {
String key = tenantContext.requiredTenantId() + ":" + id;
Product cached = products.get(key);
if (cached != null) {
return cached;
}
Product product = repository.findById(id).orElseThrow();
products.put(key, product);
return product;
}
業務域可以用 CacheBuilder 建立自己的 bean;不需要先複製一個通用
UserCacheService 或 SessionCacheService wrapper。
tenantless 模組不要照抄 TenantContext;key 應依該領域真正的 application/owner/resource
scope 組成。若資料本來就是 application-scoped,直接用 business id 即可。
覆寫預設
Feature 對可替換 SPI 採「預設 bean + missing-bean override」:
- auth 預設
CacheTokenBlacklistStore,改用 Redis 時提供自己的TokenBlacklistStore。 - signed-link 預設
CacheSignedLinkStore,改用資料庫時提供自己的SignedLinkStore。 - service-account 預設
CacheClientCredentialsRateLimiter,由 gateway 限流時提供自己的ClientCredentialsRateLimiter。
因此 reference implementation 只在產品真的偏離預設時才需要程式碼。
多節點部署
本 reference implementation 的 Ehcache persistence 僅供單節點使用:
# 每個節點各自獨立,禁止 NFS/共享磁碟共用同一目錄
app:
cache:
path: /srv/app-node-1/var/cache
需要叢集一致時,替換用途 SPI,而不是共享 Ehcache 目錄:
TokenBlacklistStore→ Redis/DBClientCredentialsRateLimiter→ Redis atomic counter/API gatewaySignedLinkStore→ 具原子 consume 的 DB/Redis 實作
登入鎖定目前直接消費 Cache<String, AttemptRecord>,可在應用組裝層提供分散式 cache
adapter。OIDC exchange 不使用共用 cache Feature;它有獨立 OidcExchangeStore SPI,
reference implementation 以 JPA row lock 保證跨節點原子 consume。