[← README](../README.md) · [next: the three annotations →](02-the-three-annotations.md) # 1. What the Spring cache abstraction actually is It is an interceptor and a map interface. That is the whole idea, and holding onto it explains almost every surprise later. When a bean carries `@Cacheable`, Spring does not modify the class. It places an AOP proxy in front of it and puts a `CacheInterceptor` in the chain. On each call the interceptor: 1. asks a `KeyGenerator` for a key, 2. asks a `Cache` (looked up from a `CacheManager` by name) whether it holds that key, 3. returns the stored value if it does, and otherwise calls the real method and stores the result. `org.springframework.cache.Cache` is a small interface — `get`, `put`, `evict`, `evictIfPresent`, `clear`, `invalidate`, `retrieve`. Everything you associate with a cache product — expiry, size limits, eviction policy, replication, persistence, statistics — lives behind that interface in a provider. The abstraction itself has none of it. The reference documentation is explicit about this in its "How can I set the TTL/TTI/eviction policy" section: you configure it on the provider. ## What that buys you Portability of the *declaration*, not the behaviour. The same annotated method runs against a `ConcurrentHashMap` in a unit test, Caffeine in one deployment and Redis in another, without the service code changing. That is genuinely useful and it is the main reason to use it. ## When not to cache - **The method is not slow.** A cache turns a 2 ms call into a 0.1 ms call and adds a correctness problem. Measure first. - **The data must be correct right now.** Balances, stock levels, permissions. A cache is a deliberate decision to serve stale data; make it deliberately. - **The hit rate will be low.** A cache keyed on something nearly unique — a search phrase, a request id — is a memory leak wearing a performance costume. - **The value is huge and the memory budget is not.** On the default provider nothing evicts. `docs/output/01-basics.txt` has the smallest possible demonstration: 200 ms, then 0 ms, with the repository's invocation counter proving the method body did not run the second time. ## The two caches people confuse If you are using JPA, you already have caching whether you asked for it or not: the persistence context (first level) and possibly Hibernate's second-level cache. They are a different thing from this, at a different layer, with different failure modes. [Chapter 9](09-versus-hibernate-l2.md) is the comparison.