Caffeine in Spring Boot

Caffeine is a high-performance, near-optimal caching library for Java that integrates very well with Spring Boot. It provides features like size-based eviction, time-based expiration, refresh, and statistics.

Here’s a step-by-step guide with example:


1. Add Dependencies

In Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version> <!-- use latest -->
</dependency>

In Gradle:

implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'

2. Enable Caching in Spring Boot

Add @EnableCaching in your main application class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class CaffeineCacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(CaffeineCacheApplication.class, args);
    }
}

3. Configure Caffeine Cache

You can configure via application.yml:

spring:
  cache:
    cache-names: users
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=5m

Or define a CaffeineCacheManager bean:

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class CacheConfig {

    @Bean
    public Caffeine<Object, Object> caffeineConfig() {
        return Caffeine.newBuilder()
                .expireAfterWrite(5, TimeUnit.MINUTES)
                .maximumSize(1000);
    }

    @Bean
    public CacheManager cacheManager(Caffeine<Object, Object> caffeine) {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("users");
        cacheManager.setCaffeine(caffeine);
        return cacheManager;
    }
}

4. Use Cache in a Service

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Cacheable("users")
    public String getUserById(String userId) {
        simulateSlowService(); // simulate DB call
        return "User-" + userId;
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

5. Test the Cache

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user/{id}")
    public String getUser(@PathVariable String id) {
        return userService.getUserById(id);
    }
}

🔍 What happens:

  • First request to /user/123 → takes ~3s (simulated DB call).
  • Next requests to /user/123 → return instantly (from cache).
  • After 5 minutes (or when cache size exceeds 1000 entries), the cache entry expires.

Leave a Reply