Backend Development 12 min read

Mastering Caffeine Cache in Spring Boot 3.2: Performance, Eviction & Async Usage

This article introduces the high‑performance Caffeine caching library for Spring Boot 3.2, explains its core features, demonstrates detailed performance benchmarks, and provides practical code examples covering synchronous and asynchronous operations, eviction policies, removal listeners, refresh mechanisms, and statistics collection.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Caffeine Cache in Spring Boot 3.2: Performance, Eviction & Async Usage

1. Introduction

Caffeine is a high‑performance Java 8‑based caching library that offers near‑optimal hit rates. Unlike a plain ConcurrentMap, a Caffeine Cache can be configured to evict entries automatically, and its LoadingCache and AsyncLoadingCache provide convenient automatic loading.

Features

Automatic loading of elements, with optional asynchronous loading.

Capacity‑based eviction using near‑frequency algorithms.

Time‑based eviction based on last access or write.

Asynchronous refresh on stale reads.

Keys are wrapped with weak references.

Values can be wrapped with weak or soft references.

Eviction or removal notifications.

Write‑through to an external data source.

Cache access statistics collection.

2. Performance Test

Benchmarks were run with Java Microbenchmark Harness (JMH). The “generation” test measures the cost of locking when creating cache entries. The “read” test uses 8 threads reading from a cache with a maximum size. The “write” test uses 8 threads performing concurrent writes.

Read test (75% reads / 25% writes) uses 6 reader threads and 2 writer threads.

Write test (100% writes) uses 8 writer threads.

3. Practical Examples

3.1 Add Dependency

<code><dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
</dependency>
</code>

3.2 Adding Elements

Synchronous operations

<code>static final Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    // expire after 10 minutes regardless of usage
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .maximumSize(10_000)
    .build();

public static void basicCache() {
    User user = cache.getIfPresent(1L);
    user = cache.get(1L, key -> new User(key, "Zhang San", 22));
    cache.put(1L, user);
    cache.invalidate(1L);
}
</code>

Asynchronous operations

<code>static AsyncCache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .maximumSize(10_000)
    .buildAsync();

public static void asyncCache() {
    CompletableFuture&lt;User&gt; cf = cache.getIfPresent(1L);
    cf.thenAccept(System.out::println);
    cf = cache.get(1L, key -> new User(key, "Zhang San", 22));
    cache.put(1L, CompletableFuture.supplyAsync(() -> new User(1L, "Li Si", 33)));
    cache.synchronous().invalidate(1L);
}
</code>

3.3 Eviction Strategies

Caffeine provides three eviction policies: capacity‑based, time‑based, and reference‑based.

Capacity‑based – evicts when the maximum size is exceeded, using near‑frequency algorithms.

<code>public static User createUser(Long key) {
    return new User(key, "name - " + key, new Random().nextInt(100));
}
public static void main(String[] args) {
    LoadingCache&lt;Long, User&gt; cache = Caffeine.newBuilder()
        .maximumSize(3)
        .build(key -> createUser(key));
    System.out.println(cache.get(1L));
    System.out.println(cache.get(2L));
    System.out.println(cache.get(3L));
    System.out.println(cache.get(4L)); // evicts key 2
}
</code>

Result shows key 2 being evicted when key 4 is inserted.

Time‑based – expireAfterAccess, expireAfterWrite, or custom Expiry.

<code>Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .expireAfterAccess(3, TimeUnit.SECONDS)
    .build();
cache.put(1L, new User(1L, "Admin", 20));
System.out.println(cache.getIfPresent(1L));
TimeUnit.SECONDS.sleep(3);
System.out.println(cache.getIfPresent(1L)); // null after 3 s
</code>

Reference‑based – keys are weakly referenced, values can be weak or soft referenced (not detailed here).

3.4 Removal

<code>static final Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .maximumSize(10)
    .build();

public static void remove(Long key) {
    cache.invalidate(key);
    cache.invalidateAll(Arrays.asList(key));
    cache.invalidateAll();
}
</code>

Listeners can be attached to receive eviction or removal callbacks.

<code>static Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .maximumSize(3)
    .evictionListener((k, v, cause) -> System.out.printf("Key %s was evicted (%s)%n", k, cause))
    .removalListener((k, v, cause) -> System.out.printf("Key %s was removed (%s)%n", k, cause))
    .build();
</code>

3.5 Refresh

<code>static final Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .refreshAfterWrite(3, TimeUnit.SECONDS)
    .maximumSize(10)
    .build(key -> createUser(key));

private static User createUser(Long key) {
    int r = new Random().nextInt(100);
    return new User(key, "China - " + r, r);
}
</code>

Refresh occurs only when the key is accessed after the refresh interval.

3.6 Statistics

<code>static final Cache&lt;Long, User&gt; cache = Caffeine.newBuilder()
    .maximumSize(10)
    .recordStats()
    .build();
CacheStats stats = cache.stats();
System.out.println("hitRate: " + stats.hitRate());
System.out.println("evictionCount: " + stats.evictionCount());
System.out.println("averageLoadPenalty: " + stats.averageLoadPenalty());
</code>

4. Comprehensive Example

For a full‑stack demonstration of Caffeine in a real Spring Boot project, refer to the linked article “Annotation + Caffeine: High‑Performance API Rate Limiting”.

JavaPerformanceCacheSpring Bootcaffeineasynceviction
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.