Skip to main content
Advertisement

2.6 Caching

For read-heavy APIs, reference data, or statistics, caching reduces DB and external calls and improves latency. Spring offers declarative caching (@Cacheable) and a CacheManager abstraction.

Reference: Spring Boot 3.2.x, spring-boot-starter-cache

1. Dependency and Enabling Cache

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-cache'
}
@SpringBootApplication
@EnableCaching // enable caching
public class Application { ... }

Use Caffeine for in-memory cache without a separate server.

implementation 'com.github.ben-manes.caffeine:caffeine'
spring:
cache:
type: caffeine
cache:
caffeine:
spec: maximumSize=500,expireAfterWrite=10m
  • maximumSize=500: Keep up to 500 entries
  • expireAfterWrite=10m: Expire 10 minutes after write

3. @Cacheable

Cache method return values; repeated calls with the same arguments are served from cache.

@Service
public class ProductService {

@Cacheable(value = "products", key = "#id")
public Product findById(Long id) {
return productRepository.findById(id).orElseThrow();
}

@Cacheable(value = "productList", key = "#categoryId + '-' + #page")
public List<Product> findByCategory(Long categoryId, Pageable page) {
return productRepository.findByCategoryId(categoryId, page);
}
}
  • value: Cache name (namespace)
  • key: Cache key as SpEL expression. Omit to use default key derived from arguments.

4. @CacheEvict

Remove cache entries when data changes.

@CacheEvict(value = "products", key = "#product.id")
public void update(Product product) {
productRepository.save(product);
}

@CacheEvict(value = "products", allEntries = true) // clear entire cache
public void deleteAllByCategory(Long categoryId) {
productRepository.deleteByCategoryId(categoryId);
}
  • allEntries = true: Delete all entries for the given cache name

5. @CachePut

Always run the method and put/overwrite the return value in cache. Use this to "reflect changes in cache immediately after saving".

@CachePut(value = "products", key = "#result.id")
public Product save(Product product) {
return productRepository.save(product);
}

6. Redis (Distributed)

For multiple servers sharing the same cache, use Redis.

implementation 'org.springframework.boot:spring-boot-starter-data-redis'
spring:
cache:
type: redis
data:
redis:
host: localhost
port: 6379
  • Keep @Cacheable, @CacheEvict etc. as-is and simply switch CacheManager to Redis.
  • Set TTL via Redis config or RedisCacheConfiguration corresponding to each @Cacheable cache name.

7. condition and unless

  • condition: SpEL; only cache when true.
  • unless: SpEL; do not cache when true.
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User findById(Long id) { ... }

tip

If the cache key is simple, key can be omitted. For complex keys or null exclusion, use condition/unless. For Redis, always set TTL and memory policy appropriate for your production environment.

Advertisement