How Caffeine can boost your Spring caching capabilities

posted 2 min read

Caffeine caching on Spring Boot

Hello guys. This is a quick tutorial to get you started with Caffeine caching on Spring Boot

Context and background: I'm developing a REST API that needs to decodes and authenticate users using Auth0 and OAuth2. The issue is that I have to call the /userinfo endpoint for every request I get from the client, given a JWT token, to get the user information. The JWT token itself doesn't have the user details.

The consequent problem is that Auth0 API has limits to prevent high usage, and I started getting 400, leading the back-end either broken or not property authenticated.

To solve this issue, I added Caffeine, a simple but effective cache system for Spring. It works with just a few line of codes. Here's how you can implement on your Spring project:

<!-- First add the dependency on pom.xml -->
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
</dependency>

Then

/* enable Caching on your Spring Application adding the annotation as follow */

import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
public class MyApplication {
  /* rest of the code */
}
/* Then create a CacheConfig class to hold the caching configuration */

package my.package;

import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Configuration class for caching using Caffeine. This class sets up a cache manager with specified
 * time-to-live and maximum size for the cache.
 */
@Slf4j
@Configuration
@EnableCaching
public class CacheConfig {

  @Value("${cache.auth0.ttl-minutes}")
  private int ttlMinutes;

  @Value("${cache.auth0.max-size:1000}")
  private int maxSize;

  @Value("${cache.auth0.access-ttl-minutes:10}")
  private int accessTtlMinutes;

  /**
   * Configures a Caffeine cache manager with specified settings.
   *
   * @return a configured CacheManager instance.
   */
  @Bean
  public CacheManager cacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager("userInfoDto");
    cacheManager.setCaffeine(caffeineCacheBuilder());
    return cacheManager;
  }

  /**
   * Builds a Caffeine cache configuration with size and time-based eviction policies.
   *
   * @return a Caffeine cache builder instance.
   */
  @Bean
  public Caffeine<Object, Object> caffeineCacheBuilder() {
    return Caffeine.newBuilder()
        .maximumSize(maxSize)
        .expireAfterWrite(ttlMinutes, TimeUnit.MINUTES)
        .expireAfterAccess(accessTtlMinutes, TimeUnit.MINUTES)
        .recordStats()
        .removalListener(
            (key, value, cause) -> {
              log.info("Cache entry removed: {}", cause);
            });
  }
}

And finally:

/* Add the @Cacheable annotation in the method you want to cache */

@Service
public class AuthService {
  
  /* other members and constructor */

  @Cacheable(value = "userInfoDto", key = "#token")
  public Optional<UserInfoDto> getUserInfo(String token) {
    /* rest of the code */
  }
}

That's it. Now you should have a fully working caching, simple but effective.

You can have a minimum control over the caching TTL, maximum size, and access TTL in minutes through configurations directly in the application.properties file, here's an example:

cache.auth0.ttl-minutes = 300
cache.auth0.max-size = 1000
cache.auth0.access-ttl-minutes = 300

Thank you for reading. See you in the next article!

0 votes
0 votes

More Posts

Let's understand Retries in Spring Boot

Madhu - Oct 17

Designing APIs for the AI Era with Spring AI and MCP

David Lopez Felguera - Sep 22

Upgrading JJWT on Spring Boot 3.3.x for GraalVM and Cloud Native

Ricardo Campos - Sep 3

Saga Pattern — an Introduction

Raj Kundalia - Aug 17

Mailgun API returning 401

Ricardo Campos - Jun 27
chevron_left