[← what caching is](01-what-caching-is.md) · [next: self-invocation →](03-self-invocation.md) # 2. The annotations, attribute by attribute Verified against `spring-context` 7.0.9 with `javap`, so this is what the class files declare rather than what the documentation summarises. ## `@Cacheable` | Attribute | Type | Notes | |---|---|---| | `value` / `cacheNames` | `String[]` | Aliases. Several names means several caches are consulted and all of them written. | | `key` | `String` | SpEL. Mutually exclusive with `keyGenerator`; setting both fails the context at startup. | | `keyGenerator` | `String` | Bean name of a `KeyGenerator`. | | `cacheManager` | `String` | Bean name, for when there is more than one. | | `cacheResolver` | `String` | Full control over which caches this operation uses. Mutually exclusive with `cacheManager`. | | `condition` | `String` | SpEL, evaluated **before** the call. False means no lookup and no write. | | `unless` | `String` | SpEL, evaluated **after**. Can see `#result`. Vetoes the write only. | | `sync` | `boolean` | One caller computes, the rest wait. Heavily restricted — see [chapter 7](07-sync-and-async.md). | ## `@CachePut` Same attributes minus `sync`. Always invokes the method, always writes the result. Use it when you already have the new value and want to avoid the miss that an eviction would cause. Do not put `@CachePut` and `@Cacheable` on the same method. The framework does not stop you, and the two have opposite intentions. ## `@CacheEvict` Same as `@Cacheable` minus `unless` and `sync`, plus: | Attribute | Type | Notes | |---|---|---| | `allEntries` | `boolean` | Clears the whole region in one operation instead of key by key. | | `beforeInvocation` | `boolean` | Default `false` — evict after a *successful* return. See [chapter 5](05-eviction.md). | `void` is fine here; the annotation is a trigger and the return value is ignored. ## `@Caching` A container for several operations of the same type on one method: ```java @Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames = "secondary", key = "#p0") }) public Book importBooks(String deposit, Date date) { ... } ``` ## `@CacheConfig` Class-level defaults for `cacheNames`, `keyGenerator`, `cacheManager` and `cacheResolver`. It enables nothing on its own. Precedence runs global (`CachingConfigurer`) → class (`@CacheConfig`) → operation, with the operation always winning. ## `@EnableCaching` Exactly three attributes, and this is worth knowing because a popular piece of advice uses a fourth that does not exist: ``` AdviceMode mode() int order() boolean proxyTargetClass() ``` There is no `exposeProxy`. `@EnableCaching(exposeProxy = true)` does not compile. `docs/output/04-non-public-and-postconstruct.txt` prints the reflected attribute list. Spring Boot's reference documentation advises against putting `@EnableCaching` on the main application class, because it makes caching mandatory for every test slice too. Put it on a `@Configuration` class you can exclude. ## Declarations that are rejected, and when `docs/output/20-invalid-declarations.txt` runs five bad declarations through a real context. Only the first fails at startup: | Declaration | Fails | |---|---| | `key` and `keyGenerator` together | at startup | | `sync = true` with `unless` | at the first call | | `sync = true` across two caches | at the first call | | `sync = true` combined with another cache operation | at the first call | | a cache name not in `spring.cache.cache-names` | at the first call | Four of the five start a healthy-looking application and throw on a code path that may not run for hours. That is the single strongest argument for having a test that actually calls each cached method.