Caffeine In-Memory Cache

Why Caffeine

Caffeine is a fast in-process cache with size limits, TTL and statistics. It is the best choice when you run one instance, or when slightly different data on different servers is acceptable.

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

Example

application.yml

spring:
  cache:
    type: caffeine
    cache-names: products,productsByCategory
    caffeine:
      spec: maximumSize=10000,expireAfterWrite=10m,recordStats

Different TTL per Cache

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    CacheManager cacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.registerCustomCache("products",
            Caffeine.newBuilder().maximumSize(10_000).expireAfterWrite(Duration.ofMinutes(10)).recordStats().build());
        manager.registerCustomCache("stock",
            Caffeine.newBuilder().maximumSize(10_000).expireAfterWrite(Duration.ofSeconds(15)).build());
        return manager;
    }
}

Size-Limited LRU in Plain Java

Example

Caffeine evicts the least useful entries when full. A LinkedHashMap in access order gives a simple LRU with the same idea:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        LruCache<String, String> cache = new LruCache<>(3);
        cache.put("p1", "Pixel 9");
        cache.put("p2", "iPhone 16");
        cache.put("p3", "Galaxy S25");
        cache.get("p1");                       // p1 is now most recently used
        cache.put("p4", "OnePlus 13");         // full: evicts p2 (least recently used)
        System.out.println("keys in cache: " + cache.keySet());
    }
}

class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int max;
    LruCache(int max) { super(16, 0.75f, true); this.max = max; }
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        boolean evict = size() > max;
        if (evict) System.out.println("evicting " + eldest.getKey());
        return evict;
    }
}

Output

evicting p2
keys in cache: [p3, p1, p4]