Caching with @Cacheable

Spring Boot · lesson 22 of 39 · 3 min read

Skip expensive work with the cache abstraction, and evict entries before they go stale.

Open this lesson in the learning hub

Key points

  • Add @EnableCaching, then @Cacheable on the method. On a hit the body is never executed.
  • The key comes from the arguments by default. Give an explicit key expression when that is not what you want.
  • @CacheEvict drops an entry after a write; @CachePut always runs the method and refreshes the entry.
  • With no cache library on the classpath Boot uses a ConcurrentHashMap - unbounded, and per instance.
  • Add Caffeine with a size and a TTL for one node, or Redis when several instances must share the cache.
  • It is proxy based, so a cached method called through this is not cached, and never expiring is not a cache.

Example

@Configuration
@EnableCaching
class CacheConfig { }

@Service
public class RateService {

    @Cacheable(cacheNames = "rates", key = "#currency")
    public Rate lookup(String currency) {
        return remote.fetch(currency);       // only runs on a miss
    }

    @CachePut(cacheNames = "rates", key = "#rate.currency()")
    public Rate refresh(Rate rate) {
        return remote.push(rate);            // always runs, then updates the entry
    }

    @CacheEvict(cacheNames = "rates", allEntries = true)
    public void clear() { }
}

// application.yml - bound size and TTL, because an unbounded cache is a leak:
//   spring.cache.cache-names: rates
//   spring.cache.caffeine.spec: maximumSize=10000,expireAfterWrite=5m

A cache hit skips your method entirely, so bound the size, set a TTL, and own the staleness.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.