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.