A Spring Boot 4.1.1 module whose test suite is the evidence for the article: 19 tests producing 22 transcripts under docs/output/, plus 12 documentation chapters. Findings the build pins: - @EnableCaching has no exposeProxy attribute; the widely-copied @EnableCaching(exposeProxy = true) does not compile. - Two methods sharing a cache name and an argument type share a key space, and one silently serves the other's answers. - beforeInvocation = true is NOT deferred by TransactionAwareCacheManagerProxy on 7.0.9 - doEvict picks evictIfPresent, which the decorator does not intercept. - Four of five invalid declarations start a clean context and throw at the first call. - Caffeine on the classpath silently displaces the simple provider.
3.7 KiB
← what caching is · next: self-invocation →
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. |
@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. |
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:
@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.