التخزين المؤقت داخل الذاكرة وضبط Caffeine
تهيئة سياسات الإخلاء وانتهاء الصلاحية والحجم في Caffeine لذاكرات التخزين المحلية عالية الإنتاجية.
التخزين المؤقت داخل الذاكرة وضبط Caffeine درس مجاني في Spring Boot 4 Complete Guide على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Spring Boot 4 Complete Guide، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Spring Boot 4 Complete Guide 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
Why Caffeine for Local Caches
Caffeine is a high-performance, near-optimal Java caching library and the default in-memory cache for Spring Boot when it is on the classpath.
- It uses the Window TinyLFU eviction policy, which beats plain LRU on real-world hit rates.
- It supports size-based, time-based, and reference-based eviction.
- It is fully concurrent and lock-free on the read path, ideal for high-throughput services.
In this lesson you will tune Caffeine's eviction, expiry, and size policies so a local cache stays fast without exhausting heap.
Adding Caffeine to a Spring Boot 4 App
Spring Boot auto-configures Caffeine when both spring-boot-starter-cache and the caffeine dependency are present.
Then enable caching with @EnableCaching on a configuration class. Methods annotated with @Cacheable will use the Caffeine-backed CacheManager.
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
// CaffeineCacheManager is auto-configured
// when com.github.ben-manes.caffeine:caffeine is on the classpath
}Maximum Size Eviction
The most common policy for a local cache is bounded size. Use maximumSize to cap the number of entries; Caffeine evicts the least valuable entries (Window TinyLFU) once the bound is exceeded.
- Pick a size that fits comfortably in heap given your value object footprint.
- Eviction is not immediate at the boundary; it happens promptly but asynchronously.
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
@Bean
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager("products");
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(10_000)
.recordStats());
return manager;
}Weight-Based Eviction
When entries vary wildly in size, bound the cache by weight instead of count. Provide a maximumWeight and a Weigher that returns each entry's cost.
- You cannot combine
maximumSizeandmaximumWeighton the same cache. - Weights are computed once at insertion and are not updated afterward.
import com.github.benmanes.caffeine.cache.Caffeine;
Caffeine.newBuilder()
.maximumWeight(50_000_000) // ~50MB budget
.weigher((String key, byte[] value) -> value.length)
.build();expireAfterWrite vs expireAfterAccess
Time-based expiry comes in two flavors:
- expireAfterWrite: entry expires a fixed duration after it was created or last replaced. Best for data with a known freshness window (e.g. a price valid for 5 minutes).
- expireAfterAccess: entry expires a duration after its last read or write. Best for keeping hot data alive and dropping idle entries.
You may combine both; the entry expires when either condition fires first.
import com.github.benmanes.caffeine.cache.Caffeine;
import java.time.Duration;
Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(Duration.ofMinutes(5))
.expireAfterAccess(Duration.ofMinutes(2))
.build();Configuring via application.properties
For a single shared spec, Spring Boot lets you skip Java config and use the spring.cache.caffeine.spec property. It accepts the comma-separated Caffeine spec string.
This is convenient but applies the same spec to every cache name; per-cache tuning still requires a programmatic CaffeineCacheManager or a custom CacheLoader.
spring.cache.type=caffeine
spring.cache.cache-names=products,prices
spring.cache.caffeine.spec=maximumSize=10000,expireAfterWrite=5m,recordStatsrefreshAfterWrite for Stale-While-Revalidate
refreshAfterWrite differs from expiry: instead of removing the entry, it asynchronously reloads it after the duration while still serving the old value. This avoids a latency spike on the first request after staleness.
- It requires a
LoadingCache(a cache built with aCacheLoader). - Only one thread triggers the refresh; others keep reading the existing value.
- Combine with a longer
expireAfterWriteas a hard ceiling.
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.time.Duration;
LoadingCache<String, String> cache = Caffeine.newBuilder()
.refreshAfterWrite(Duration.ofMinutes(1))
.expireAfterWrite(Duration.ofMinutes(10))
.build(key -> loadFromDatabase(key));A Standalone Caffeine Demo
Here is a complete, framework-free program demonstrating maximumSize eviction. Insert more entries than the bound and observe that the cache never exceeds its size after cleanup.
This is the kind of micro-benchmark you can run to validate a tuning choice before wiring it into Spring.
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class CaffeineDemo {
public static void main(String[] args) {
Cache<Integer, String> cache = Caffeine.newBuilder()
.maximumSize(3)
.build();
for (int i = 0; i < 10; i++) {
cache.put(i, "value-" + i);
}
cache.cleanUp(); // force pending eviction work
System.out.println("Estimated size: " + cache.estimatedSize());
System.out.println("Get key 9: " + cache.getIfPresent(9));
}
}Per-Cache Tuning with Custom Specs
Real services need different policies per cache: a tiny hot lookup table vs a large warm dataset. Subclass or configure CaffeineCacheManager so each name gets its own builder.
One clean approach is registering individual native caches by name on the manager.
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import java.time.Duration;
@Bean
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.registerCustomCache("prices", Caffeine.newBuilder()
.maximumSize(1_000)
.expireAfterWrite(Duration.ofSeconds(30))
.build());
manager.registerCustomCache("catalog", Caffeine.newBuilder()
.maximumSize(100_000)
.expireAfterAccess(Duration.ofHours(1))
.build());
return manager;
}Measuring Hit Rate with recordStats
You cannot tune what you do not measure. Enable recordStats() to expose CacheStats: hit count, miss count, eviction count, and average load penalty.
- A low hit rate suggests the cache is too small or the keys too cardinal.
- High eviction with high miss rate means
maximumSizeis starving the working set. - Spring Boot's Micrometer integration publishes these as metrics when stats are on.
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
public class StatsDemo {
public static void main(String[] args) {
Cache<String, Integer> cache = Caffeine.newBuilder()
.maximumSize(2)
.recordStats()
.build();
cache.put("a", 1);
cache.getIfPresent("a"); // hit
cache.getIfPresent("b"); // miss
CacheStats stats = cache.stats();
System.out.printf("hits=%d misses=%d rate=%.2f%n",
stats.hitCount(), stats.missCount(), stats.hitRate());
}
}Avoiding Common Tuning Pitfalls
A few traps to watch for under high throughput:
- Unbounded caches: never build a cache without a size or expiry bound, or you risk an
OutOfMemoryError. - initialCapacity: set it near the expected steady-state size to avoid resize churn on the read-heavy path.
- Soft/weak references:
softValues()ties eviction to GC pressure, which is unpredictable; prefer explicit size/time bounds for latency-sensitive caches. - refreshAfterWrite without a loader: it silently has no effect on a manual cache.
Quick Check: Choosing an Expiry Policy
You cache product prices that the upstream system guarantees are valid for exactly 5 minutes after publication. Reads are frequent but you must never serve a price older than 5 minutes. Which Caffeine policy fits best?
Recap
You tuned Caffeine for high-throughput local caching in Spring Boot 4:
- Size:
maximumSizefor uniform entries,maximumWeight+Weigherfor variable cost. - Time:
expireAfterWritefor freshness contracts,expireAfterAccessto keep hot data, combine for both ceilings. - Refresh:
refreshAfterWriteon aLoadingCachefor stale-while-revalidate without latency spikes. - Config:
spring.cache.caffeine.specfor one shared spec, orregisterCustomCachefor per-cache tuning. - Measure: always enable
recordStats()and watch hit rate and eviction count to guide further tuning.
تعلم Java مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 21
- الدروس
- 84
الأسئلة الشائعة
هل درس «التخزين المؤقت داخل الذاكرة وضبط Caffeine» مجاني؟
نعم — نص درس «التخزين المؤقت داخل الذاكرة وضبط Caffeine» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Spring Boot 4 Complete Guide، انتقل إلى CoddyKit PRO. تتضمن دورة Spring Boot 4 Complete Guide 4 دروس في المجموع.
ماذا ستتعلم في «التخزين المؤقت داخل الذاكرة وضبط Caffeine»؟
تهيئة سياسات الإخلاء وانتهاء الصلاحية والحجم في Caffeine لذاكرات التخزين المحلية عالية الإنتاجية. تتمرن على Spring Boot 4 Complete Guide مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Spring Boot 4 Complete Guide؟
لا تُشترط خبرة سابقة. Spring Boot 4 Complete Guide على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «التخزين المؤقت داخل الذاكرة وضبط Caffeine»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Spring Boot 4 Complete Guide هذا؟
نعم. كل درس في Spring Boot 4 Complete Guide يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات تجريد التخزين المؤقت في Spring
- التخزين المؤقت داخل الذاكرة وضبط Caffeine
- التخزين المؤقت الموزّع باستخدام Redis وTTLs
- اندفاع التخزين المؤقت والإبطال والاتساق