Caching with @Cacheable

Spring's caching abstraction lets a single annotation — @Cacheable — remember an expensive method's result, while @CacheEvict keeps it fresh and providers like Caffeine or Redis do the storing.

Learn Caching with @Cacheable in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

You should understand Spring beans and services , and be comfortable with maps and lambdas for the memoization demos.

💡 Analogy: Imagine someone keeps asking you for the office Wi-Fi password. The first time you walk to IT and fetch it (the expensive call); then you scribble it on a sticky note on your monitor. Every later request is answered instantly from the note — that's @Cacheable . But when IT changes the password, the note is now wrong , so you must tear it down and write the new one: that's @CacheEvict . The note can live on your own desk ( Caffeine , fast but only yours) or on a shared whiteboard everyone can see ( Redis , slower to reach but shared by the whole team).

Fetch the slow answer once, reuse it cheaply — and remember to update the note when the truth changes.

@Cacheable is memoization: store a method's result keyed by its arguments so the expensive work happens once per key. The plain-Java demo uses computeIfAbsent to make that mechanism explicit.

A cache speeds reads but can go stale . When the source data changes you must remove the old entry — that's @CacheEvict . Forget it and readers keep seeing the outdated value.

Turn caching on once with @EnableCaching , then annotate methods: @Cacheable to read-through, @CacheEvict to invalidate, @CachePut to refresh. Spring applies the logic via AOP proxies.

Spring caches against whatever provider is on the classpath. Caffeine is a fast in-process cache for a single instance; Redis is a distributed cache shared across instances and surviving restarts.

Answer: no — it's a cache hit, so the stored value is returned and the body is skipped.

Answer: @CacheEvict (or @CachePut ) on the write removes/refreshes the affected entry.

Answer: Redis — a distributed cache. Caffeine is local to a single JVM.

🎯 YOUR TURN — Memoized Fibonacci

Complete fib(n) using the cache map so each n is computed only once.

🧩 MINI-CHALLENGE — Read-Through Cache with Eviction

Implement get (cache-through) and set (update + evict) and prove the read after a set is fresh.

You now understand how @Cacheable memoizes results by key, how keys are derived, how @CacheEvict and @CachePut keep data fresh, how @EnableCaching turns it all on, and when to choose Caffeine versus Redis.

Next up: Containerizing a Spring Boot App — Dockerfiles, layered jars, and buildpacks.

Practice quiz

What does @Cacheable do?

  • Deletes a cache
  • Stores a method's result so subsequent calls with the same key return the cached value
  • Encrypts the result
  • Runs the method twice

Answer: Stores a method's result so subsequent calls with the same key return the cached value. @Cacheable caches the return value keyed by the method arguments; later matching calls skip the method body and return the cached value.

Which annotation enables Spring's caching abstraction?

  • @EnableCaching
  • @StartCache
  • @CacheOn
  • @Caching

Answer: @EnableCaching. You add @EnableCaching to a configuration class to turn on Spring's annotation-driven caching.

What forms the default cache key for a @Cacheable method?

  • The method name
  • The current time
  • The method's parameters
  • A random UUID

Answer: The method's parameters. By default the key is derived from the method arguments; you can customise it with a SpEL key expression.

What does @CacheEvict do?

  • Adds an entry
  • Reads an entry
  • Locks the cache
  • Removes one or all entries from a cache (e.g. after an update)

Answer: Removes one or all entries from a cache (e.g. after an update). @CacheEvict removes entries so stale data is purged — for example when the underlying record changes.

When a @Cacheable method is called a SECOND time with the same arguments...

  • The method body runs again
  • The cached value is returned and the body is skipped
  • An exception is thrown
  • The cache is cleared

Answer: The cached value is returned and the body is skipped. A cache hit returns the stored value without executing the method body — that is the whole point.

Which of these is a common cache provider used with Spring?

  • Caffeine
  • Tomcat
  • Jackson
  • Log4j

Answer: Caffeine. Caffeine is a popular high-performance in-memory cache; Redis is common for distributed caching.

Why might you choose Redis over an in-memory cache like Caffeine?

  • It is simpler to set up
  • It needs no network
  • It is a distributed cache shared across multiple app instances
  • It is always faster

Answer: It is a distributed cache shared across multiple app instances. Redis is an external, shared cache, so multiple application instances see the same cached data — useful when scaling out.

What does @CachePut do?

  • Always skips the method
  • Deletes the cache
  • Disables caching
  • Always executes the method and updates the cache with the result

Answer: Always executes the method and updates the cache with the result. @CachePut runs the method every time and stores its result, keeping the cache in sync without short-circuiting.

A risk of caching is...

  • Slower reads
  • Serving stale data if entries aren't evicted/expired correctly
  • Higher network usage always
  • It breaks compilation

Answer: Serving stale data if entries aren't evicted/expired correctly. Caches can return outdated values; correct eviction, TTLs, and invalidation keep cached data fresh.

Spring's caching is implemented via...

  • bytecode rewriting at runtime by the JVM
  • proxies/AOP that intercept the method call
  • a separate thread per cache
  • database triggers

Answer: proxies/AOP that intercept the method call. Spring uses AOP proxies to intercept calls to cacheable methods and apply the cache logic around them.