--- name: spring-boot-cache description: Instruction set for enabling and operating the Spring Cache abstraction in Spring Boot when implementing application-level caching for performance-sensitive workloads. allowed-tools: Read, Write, Bash category: backend tags: [spring-boot, caching, performance, cacheable, cache-managers] version: 1.1.0 --- # Spring Boot Cache Abstraction ## Overview Spring Boot ships with a cache abstraction that wraps expensive service calls behind annotation-driven caches. This abstraction supports multiple cache providers (ConcurrentMap, Caffeine, Redis, Ehcache, JCache) without changing business code. The skill provides a concise workflow for enabling caching, managing cache lifecycles, and validating behavior in Spring Boot 3.5+ services. ## When to Use - Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to Spring Boot service methods. - Configure Caffeine, Redis, or JCache cache managers for Spring Boot. - Diagnose cache invalidation, eviction scheduling, or cache key issues. - Expose cache management endpoints or scheduled eviction routines. Use trigger phrases such as **"implement service caching"**, **"configure CaffeineCacheManager"**, **"evict caches on update"**, or **"test Spring cache behavior"** to load this skill. ## Prerequisites - Java 17+ project based on Spring Boot 3.5.x (records encouraged for DTOs). - Dependency `spring-boot-starter-cache`; add provider-specific starters as needed (`spring-boot-starter-data-redis`, `caffeine`, `ehcache`, etc.). - Constructor-injected services that expose deterministic method signatures. - Observability stack (Actuator, Micrometer) when operating caches in production. ## Quick Start 1. **Add dependencies** ```xml org.springframework.boot spring-boot-starter-cache com.github.ben-manes.caffeine caffeine ``` ```gradle implementation "org.springframework.boot:spring-boot-starter-cache" implementation "com.github.ben-manes.caffeine:caffeine" ``` 2. **Enable caching** ```java @Configuration @EnableCaching class CacheConfig { @Bean CacheManager cacheManager() { return new CaffeineCacheManager("users", "orders"); } } ``` 3. **Annotate service methods** ```java @Service @CacheConfig(cacheNames = "users") class UserService { @Cacheable(key = "#id", unless = "#result == null") User findUser(Long id) { ... } @CachePut(key = "#user.id") User refreshUser(User user) { ... } @CacheEvict(key = "#id", beforeInvocation = false) void deleteUser(Long id) { ... } } ``` 4. **Verify behavior** - Run focused unit tests that call cached methods twice and assert repository invocations. - Inspect Actuator `cache` endpoint (if enabled) for hit/miss counters. ## Implementation Workflow ### 1. Define Cache Strategy - Map hot-path read operations to `@Cacheable`. - Use `@CachePut` on write paths that must refresh cache entries. - Apply `@CacheEvict` (`allEntries = true` when invalidating derived caches). - Combine operations with `@Caching` to keep multi-cache updates consistent. ### 2. Shape Cache Keys and Conditions - Generate deterministic keys via SpEL (e.g. `key = "#user.id"`). - Guard caching with `condition = "#price > 0"` for selective caching. - Prevent null or stale values with `unless = "#result == null"`. - Synchronize concurrent updates via `sync = true` when needed. ### 3. Manage Providers and TTLs - Configure provider-specific options: - Caffeine spec: `spring.cache.caffeine.spec=maximumSize=500,expireAfterWrite=10m` - Redis TTL: `spring.cache.redis.time-to-live=600000` - Ehcache XML: define `ttl` and heap/off-heap resources. - Expose cache names via `spring.cache.cache-names=users,orders,catalog`. - Avoid on-demand cache name creation in production unless metrics cover usage. ### 4. Operate and Observe Caches - Surface cache maintenance via a dedicated `CacheManagementService` with programmatic `cacheManager.getCache(name)` access. - Schedule periodic eviction for time-bound caches using `@Scheduled`. - Wire Actuator `cache` endpoint and Micrometer meters to track hit ratio, eviction count, and size. ### 5. Test and Validate - Prefer slice or unit tests with Mockito/SpyBean to ensure method invocation counts. - Add integration tests with Testcontainers for Redis/Ehcache when using external providers. - Validate concurrency behavior under load (e.g. `sync = true` scenarios). ## Advanced Options - Integrate JCache annotations when interoperating with providers that favor JSR-107 (`@CacheResult`, `@CacheRemove`). Avoid mixing with Spring annotations on the same method. - Cache reactive return types (`Mono`, `Flux`) or `CompletableFuture` values. Spring stores resolved values and resubscribes on hits; consider TTL alignment with publisher semantics. - Apply HTTP caching headers using `CacheControl` when exposing cached responses via REST. ## Examples - Load [`references/cache-examples.md`](references/cache-examples.md) for progressive scenarios (basic product cache, conditional caching, multilevel eviction, Redis integration). - Load [`references/cache-core-reference.md`](references/cache-core-reference.md) for annotation matrices, configuration tables, and property samples. ## References - [`references/spring-framework-cache-docs.md`](references/spring-framework-cache-docs.md): curated excerpts from the Spring Framework Reference Guide (official). - [`references/spring-cache-doc-snippet.md`](references/spring-cache-doc-snippet.md): narrative overview extracted from Spring documentation. - [`references/cache-core-reference.md`](references/cache-core-reference.md): annotation parameters, dependency matrices, property catalogs. - [`references/cache-examples.md`](references/cache-examples.md): end-to-end examples with tests. ## Best Practices - Prefer constructor injection and immutable DTOs for cache entries. - Separate cache names per aggregate (`users`, `orders`) to simplify eviction. - Log cache hits/misses only at debug to avoid noise; push metrics via Micrometer. - Tune TTLs based on data staleness tolerance; document rationale in code. - Guard caches that store PII or credentials with encryption or avoid caching. - Align cache eviction with transactional boundaries to prevent dirty reads. ## Constraints and Warnings - Avoid caching mutable entities that depend on open persistence contexts. - Do not mix Spring cache annotations with JCache annotations on the same method. - Ensure multi-level caches (e.g. Caffeine + Redis) maintain consistency; prefer publish/subscribe invalidation channels. - Validate serialization compatibility when caching across service instances. - Monitor memory footprint to prevent OOM when using in-memory stores. ## Related Skills - [`skills/spring-boot/spring-boot-rest-api-standards`](../spring-boot-rest-api-standards/SKILL.md) - [`skills/spring-boot/spring-boot-test-patterns`](../spring-boot-test-patterns/SKILL.md) - [`skills/junit-test/unit-test-caching`](../../junit-test/unit-test-caching/SKILL.md)