
Spring Boot Cache
- 1.8k installs
- 318 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit
Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cach
About
The spring boot cache skill Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cache hit/miss behavior, and exposes metrics via Actuator. Use when adding caching to Spring Boot services, configuring cache expiration, evicting stale data, or diagnosing cache misses. Documentation covers workflows, commands, and guardrails agents should follow when users invoke this capability. Key documented areas include Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to service methods.; Configure Caffeine, Redis, or Ehcache with TTL and capacity policies.; Implement eviction strategies for stale data.; Diagnose cache misses or invalidation issues. Reference commands include @Service; @CacheConfig(cacheNames = "users"). Use when developers or agents need structured guidance for spring boot cache tasks with evidence grounded in the bundled SKILL.md rather than generic advice. Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to service methods. Configure Caffeine, Redis, or Ehcache with TTL and capacity policies. Implement eviction strategies for stale data.
- Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to service methods.
- Configure Caffeine, Redis, or Ehcache with TTL and capacity policies.
- Implement eviction strategies for stale data.
- Diagnose cache misses or invalidation issues.
- Expose hit/miss metrics via Actuator or Micrometer.
Spring Boot Cache by the numbers
- 1,819 all-time installs (skills.sh)
- +124 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #265 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
spring-boot-cache capabilities & compatibility
- Capabilities
- add `@cacheable`, `@cacheput`, or `@cacheevict` · configure caffeine, redis, or ehcache with ttl a · implement eviction strategies for stale data. · diagnose cache misses or invalidation issues. · expose hit/miss metrics via actuator or micromet
- Use cases
- planning
What spring-boot-cache says it does
Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to service methods.
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-cacheAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.8k |
|---|---|
| repo stars | ★ 318 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit ↗ |
How do I handle spring boot cache tasks with agent guidance?
Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cach
Who is it for?
Teams needing documented spring boot cache workflows.
Skip if: Generic advice without reading bundled docs.
When should I use this skill?
Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cach
What you get
Structured workflow from spring boot cache documentation applied to the user request.
- CacheManager bean configuration
- Annotation-based cache definitions
By the numbers
- Documents 4 common CacheManager implementations: ConcurrentMap, Simple, Caffeine, and EhCache
Files
Spring Boot Cache Abstraction
Overview
6-step workflow for enabling cache abstraction, configuring providers (Caffeine, Redis, Ehcache), annotating service methods, and validating behavior in Spring Boot 3.5+ applications. Apply @Cacheable for reads, @CachePut for writes, @CacheEvict for deletions. Configure TTL/eviction policies and expose metrics via Actuator.
When to Use
- Add
@Cacheable,@CachePut, or@CacheEvictto service methods. - Configure Caffeine, Redis, or Ehcache with TTL and capacity policies.
- Implement eviction strategies for stale data.
- Diagnose cache misses or invalidation issues.
- Expose hit/miss metrics via Actuator or Micrometer.
Instructions
1. Add dependencies — spring-boot-starter-cache plus a provider:
- Caffeine:
caffeinestarter - Redis:
spring-boot-starter-data-redis - Ehcache:
ehcachestarter
2. Enable caching — annotate a @Configuration class with @EnableCaching and define a CacheManager bean.
3. Annotate methods — @Cacheable for reads, @CachePut for writes, @CacheEvict for deletions.
4. Configure TTL/eviction — set spring.cache.caffeine.spec, spring.cache.redis.time-to-live, or spring.cache.ehcache.config.
5. Shape keys — use SpEL in key attributes; guard with condition/unless for selective caching.
6. Validate setup — run integration test to confirm cache hit on second call; check GET /actuator/caches to verify cache manager registration; query GET /actuator/metrics/cache.gets for hit/miss ratios.
Examples
Example 1: Basic @Cacheable Usage
@Service
@CacheConfig(cacheNames = "users")
class UserService {
@Cacheable(key = "#id", unless = "#result == null")
User findUser(Long id) { ... }
}First call → cache miss, repository invoked
Second call → cache hit, repository skippedExample 2: Conditional Caching with SpEL
@Cacheable(value = "products", key = "#id", condition = "#price > 100")
public Product getProduct(Long id, BigDecimal price) { ... }
// Only expensive products are cachedExample 3: Cache Eviction
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) { ... }For progressive scenarios (basic product cache, multilevel eviction, Redis integration), load `references/cache-examples.md`.
Advanced Options
- Use JCache annotations (
@CacheResult,@CacheRemove) for providers favoring
JSR-107 interoperability; avoid mixing with Spring annotations on the same method.
- Cache reactive return types (
Mono,Flux) orCompletableFuturevalues. - Apply HTTP
CacheControlheaders when exposing cached responses via REST. - Schedule periodic eviction with
@Scheduledfor time-bound caches. - Create a
CacheManagementServicefor programmaticcacheManager.getCache(name).
Troubleshooting
If cache misses persist after adding @Cacheable:
1. Verify @EnableCaching is present on a @Configuration class. 2. Confirm the method is public and called from outside the class (Spring uses proxies; self-invocation bypasses the cache). 3. Validate SpEL key expressions resolve correctly. 4. Confirm the cache manager bean is registered as cacheManager or explicitly referenced via cacheManager = "myCacheManager".
References
- `references/spring-framework-cache-docs.md`:
curated excerpts from Spring Framework Reference Guide.
- `references/spring-cache-doc-snippet.md`:
narrative overview from Spring documentation.
- `references/cache-core-reference.md`:
annotation parameters, dependency matrices, property catalogs.
- `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; push metrics via Micrometer.
- Tune TTLs based on data staleness tolerance; document rationale in code.
- Guard caches storing 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.
- Validate serialization compatibility when caching across service instances.
- Monitor memory footprint to prevent OOM with in-memory stores.
- Caffeine + Redis multi-level caches require publish/subscribe invalidation channels.
Related Skills
- `../spring-boot-rest-api-standards`
- `../spring-boot-test-patterns`
- `../unit-test-caching`
Spring Boot Cache Abstraction - References
Complete API reference and external resources for Spring Boot caching.
Spring Cache Abstraction API Reference
Core Interfaces
CacheManager
Interface for managing cache instances.
public interface CacheManager {
// Get a cache by name
Cache getCache(String name);
// Get all available cache names
Collection<String> getCacheNames();
}Common Implementations:
ConcurrentMapCacheManager- In-memory, thread-safe cachingSimpleCacheManager- Simple static cache configurationCaffeineCacheManager- High-performance caching with Caffeine libraryEhCacheManager- Enterprise caching with EhCacheRedisCacheManager- Distributed caching with Redis
Cache
Interface representing a single cache.
public interface Cache {
// Get cache name
String getName();
// Get native cache implementation
Object getNativeCache();
// Get value by key
ValueWrapper get(Object key);
// Put value in cache
void put(Object key, Object value);
// Remove entry from cache
void evict(Object key);
// Clear entire cache
void clear();
}Cache Annotations
| Annotation | Purpose | Target | Parameters |
|---|---|---|---|
@Cacheable | Cache method result before execution | Methods | value, key, condition, unless |
@CachePut | Always execute, then cache result | Methods | value, key, condition, unless |
@CacheEvict | Remove entry/entries from cache | Methods | value, key, allEntries, condition, beforeInvocation |
@Caching | Combine multiple cache operations | Methods | cacheable, put, evict |
@CacheConfig | Class-level cache configuration | Classes | cacheNames |
@EnableCaching | Enable caching support | Configuration classes | None |
Annotation Parameters
value / cacheNames
Name(s) of the cache(s) to use.
@Cacheable(value = "products") // Single cache
@Cacheable(value = {"products", "inventory"}) // Multiple cacheskey
SpEL expression to generate cache key (if not using method parameters as key).
@Cacheable(value = "products", key = "#id")
@Cacheable(value = "products", key = "#p0") // First parameter
@Cacheable(value = "products", key = "#root.methodName + #id")
@Cacheable(value = "products", key = "T(java.util.Objects).hash(#id, #name)")SpEL Context Variables:
#root.methodName- Method name being invoked#root.method- Method object#root.target- Target object#root.targetClass- Target class#root.args[0]- Method arguments array#a0,#p0- First argument#result- Method result (only in@CachePut,@CacheEvict)
condition
SpEL expression evaluated before cache operation. Operation only executes if true.
@Cacheable(value = "products", condition = "#id > 0")
@Cacheable(value = "products", condition = "#price > 100 && #active == true")
@Cacheable(value = "products", condition = "#size() > 0") // For collectionsunless
SpEL expression evaluated AFTER method execution. Entry is cached only if false.
@Cacheable(value = "products", unless = "#result == null")
@CachePut(value = "products", unless = "#result.isPrivate()")beforeInvocation
For @CacheEvict only. If true, cache is evicted BEFORE method execution (default: false).
@CacheEvict(value = "products", beforeInvocation = true) // Evict before call
@CacheEvict(value = "products", beforeInvocation = false) // Evict after callallEntries
For @CacheEvict only. If true, entire cache is cleared instead of single entry.
@CacheEvict(value = "products", allEntries = true) // Clear all entriesConfiguration Reference
Maven Dependencies
<!-- Spring Cache Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>3.5.6</version>
</dependency>
<!-- Caffeine (Optional, for advanced caching) -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.6</version>
</dependency>
<!-- EhCache (Optional, for distributed caching) -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
<classifier>jakarta</classifier>
</dependency>
<!-- Redis (Optional, for distributed caching) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.5.6</version>
</dependency>Gradle Dependencies
dependencies {
// Spring Cache Starter
implementation 'org.springframework.boot:spring-boot-starter-cache:3.5.6'
// Caffeine
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.6'
// EhCache
implementation 'javax.cache:cache-api:1.1.1'
implementation 'org.ehcache:ehcache:3.10.8'
// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.5.6'
}Application Properties (application.properties)
# General Caching Configuration
spring.cache.type=simple # Type: simple, redis, caffeine, ehcache, jcache
# Caffeine Configuration
spring.cache.caffeine.spec=maximumSize=1000,expireAfterWrite=10m
spring.cache.cache-names=products,users,orders
# Redis Configuration
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.password=
spring.cache.redis.time-to-live=600000 # 10 minutes in ms
# EhCache Configuration
spring.cache.jcache.config=classpath:ehcache.xmlApplication Properties (application.yml)
spring:
cache:
type: simple
cache-names:
- products
- users
- orders
caffeine:
spec: maximumSize=1000,expireAfterWrite=10m
redis:
time-to-live: 600000 # 10 minutes in ms
jcache:
config: classpath:ehcache.xmlPerformance Tuning Reference
Cache Types Comparison
| Type | Use Case | Memory | Thread-Safe | Distributed |
|---|---|---|---|---|
| Simple | Local, small data | Low | Yes | No |
| Caffeine | High-performance local | Medium | Yes | No |
| EhCache | Enterprise local | High | Yes | Optional |
| Redis | Distributed, large | External | Yes | Yes |
Performance Tips
1. Key Generation Strategy:
// Fast (uses method parameters directly)
@Cacheable(value = "products") // Uses all parameters as key
@Cacheable(value = "products", key = "#id") // Specific parameter
// Slower (computed SpEL)
@Cacheable(value = "products", key = "T(java.util.Objects).hash(#id, #name)")2. Cache Size Tuning:
# Caffeine: Set appropriate maximumSize
spring.cache.caffeine.spec=maximumSize=10000,expireAfterWrite=15m
# Redis: Monitor memory usage
# MEMORY STATS command in Redis CLI3. TTL Configuration:
# Redis: TTL in milliseconds
spring.cache.redis.time-to-live=600000 # 10 minutes
# Caffeine: In spec
spring.cache.caffeine.spec=expireAfterWrite=10mSpring Boot Auto-Configuration
Auto-Detected Cache Managers
Spring Boot auto-configures a CacheManager based on classpath presence (in priority order):
1. Redis - if spring-boot-starter-data-redis is present 2. Caffeine - if caffeine library is present 3. EhCache - if ehcache library is present 4. Simple - default in-memory caching
To explicitly set the cache type:
spring.cache.type=redisConditional Bean Creation
@Bean
@ConditionalOnMissingBean(CacheManager.class)
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("products", "users");
}Transaction Integration
Cache + @Transactional Interaction
@Service
@Transactional
public class ProductService {
@Cacheable(value = "products", key = "#id")
@Transactional(readOnly = true) // Combines with cache
public Product getProduct(Long id) {
return productRepository.findById(id).orElse(null);
}
@CachePut(value = "products", key = "#product.id")
@Transactional // Ensure atomicity of save + cache update
public Product updateProduct(Product product) {
return productRepository.save(product);
}
@CacheEvict(value = "products", key = "#id")
@Transactional
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
}Monitoring and Metrics
Spring Boot Actuator Integration
# Enable caching metrics
management.endpoints.web.exposure.include=metrics,health
# View cache metrics
GET http://localhost:8080/actuator/metrics
GET http://localhost:8080/actuator/metrics/cache.hits
GET http://localhost:8080/actuator/metrics/cache.missesCustom Cache Metrics
@Component
public class CacheMetricsCollector {
private final MeterRegistry meterRegistry;
public void recordCacheHit(String cacheName) {
meterRegistry.counter("cache.hits", "cache", cacheName).increment();
}
public void recordCacheMiss(String cacheName) {
meterRegistry.counter("cache.misses", "cache", cacheName).increment();
}
}EhCache XML Configuration Reference
ehcache.xml Structure
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<!-- Cache Configuration -->
<cache alias="cacheName">
<key-type>java.lang.Long</key-type>
<value-type>com.example.Product</value-type>
<!-- Time to Live -->
<expiry>
<ttl unit="minutes">30</ttl>
</expiry>
<!-- Storage Configuration -->
<resources>
<heap unit="entries">1000</heap>
<offheap unit="MB">50</offheap>
<disk unit="GB">1</disk>
</resources>
<!-- Listeners (optional) -->
<listeners>
<listener>
<class>com.example.CustomCacheEventListener</class>
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
</listener>
</listeners>
</cache>
</config>Common EhCache Attributes
heap- On-heap memory storage (fast, limited)offheap- Off-heap memory storage (slower, larger)disk- Disk storage (slowest, unlimited)ttl- Time to live before expirationidle- Time to idle before expiration (if not accessed)
Common Pitfalls and Solutions
Problem 1: Cache Not Working
Symptoms: Cache is never hit, always querying database.
Causes & Solutions:
// Problem: @Cacheable on public method called from same bean
@Service
public class ProductService {
@Cacheable("products")
public Product get(Long id) { }
public Product getDetails(Long id) {
return this.get(id); // ❌ Won't use cache (no proxy)
}
}
// Solution: Inject service or call through interface
@Service
public class DetailsService {
@Autowired
private ProductService productService;
public Product getDetails(Long id) {
return productService.get(id); // ✅ Uses cache
}
}
// Problem: Caching non-serializable objects with Redis
@Cacheable("products")
public Product get(Long id) {
Product p = new Product();
p.setConnection(dbConnection); // ❌ Not serializable
return p;
}
// Solution: Ensure all cached objects are serializable
@Cacheable("products")
public ProductDTO get(Long id) {
return mapper.toDTO(productRepository.findById(id)); // ✅ DTO is serializable
}Problem 2: Stale Cache Data
Symptoms: Updates aren't reflected in cached data.
Solution:
// Always evict cache on update
@CacheEvict(value = "products", key = "#id")
public void updateProduct(Long id, UpdateRequest req) {
Product product = productRepository.findById(id).orElseThrow();
product.update(req);
productRepository.save(product);
}
// Or use @CachePut to keep cache fresh
@CachePut(value = "products", key = "#result.id")
public Product updateProduct(Long id, UpdateRequest req) {
Product product = productRepository.findById(id).orElseThrow();
product.update(req);
return productRepository.save(product);
}Problem 3: Memory Leak
Symptoms: Memory usage grows unbounded.
Solution:
# Configure cache eviction policies
spring.cache.caffeine.spec=maximumSize=10000,expireAfterWrite=10m
# Redis: Set TTL
spring.cache.redis.time-to-live=600000
# Monitor cache sizeExternal Resources
Official Documentation
Third-Party Libraries
Related Skills
- spring-boot-performance-tuning - Comprehensive performance optimization
- spring-boot-data-persistence - Database optimization patterns
- spring-boot-rest-api-standards - API design with caching headers
Useful Articles
- Spring Cache Abstraction Tutorial
- Redis Caching in Spring Boot
- Cache Stampede Problem
- Cache Invalidation Strategies
SpEL Reference for Cache Keys
Basic Expressions
// Method parameters
@Cacheable(key = "#id") // Single parameter
@Cacheable(key = "#user.id") // Object property
@Cacheable(key = "#root.args[0]") // First argument
// Composite keys
@Cacheable(key = "#id + '-' + #type")
@Cacheable(key = "T(java.util.Objects).hash(#id, #type)")
// Collections
@Cacheable(key = "#ids.toString()")
@Cacheable(condition = "#ids.size() > 0")SpEL Context Variables
| Variable | Description |
|---|---|
#root.method | Method object |
#root.methodName | Method name |
#root.target | Target object |
#root.targetClass | Target class |
#root.args | Arguments array |
#p<index> | Argument at index |
#<name> | Named argument |
#result | Method result (@CachePut, @CacheEvict) |
Testing Reference
Testing Cache Behavior
@Test
void shouldCacheResult() {
// Arrange
when(repository.find(1L)).thenReturn(mockObject);
// Act - First call
service.get(1L);
// Assert - Database was queried
verify(repository, times(1)).find(1L);
// Act - Second call
service.get(1L);
// Assert - Database NOT queried again (cache hit)
verify(repository, times(1)).find(1L);
}Disabling Cache in Tests
@SpringBootTest
@PropertySource("classpath:application-test.properties")
class MyServiceTest {
// In application-test.properties:
// spring.cache.type=none
}Spring Boot Cache Abstraction - Examples
This document provides concrete, progressive examples demonstrating Spring Boot caching patterns from basic to advanced scenarios.
Example 1: Basic Product Caching
A simple e-commerce scenario with product lookup caching.
Domain Model
@Getter
@ToString
@EqualsAndHashCode(of = "id")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Product {
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}Service with @Cacheable
@Service
@CacheConfig(cacheNames = "products")
@RequiredArgsConstructor
@Slf4j
public class ProductService {
private final ProductRepository productRepository;
@Cacheable
public Product getProductById(Long id) {
log.info("Fetching product {} from database", id);
return productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
}
@Cacheable(key = "#name")
public Product getProductByName(String name) {
log.info("Fetching product by name: {}", name);
return productRepository.findByName(name)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
}
@CachePut(key = "#product.id")
public Product updateProduct(Product product) {
log.info("Updating product {}", product.getId());
return productRepository.save(product);
}
@CacheEvict
public void deleteProduct(Long id) {
log.info("Deleting product {}", id);
productRepository.deleteById(id);
}
@CacheEvict(allEntries = true)
public void refreshAllProducts() {
log.info("Refreshing all product cache");
}
}Test Example
@SpringBootTest
@Testcontainers
class ProductServiceCacheTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine");
@Autowired
private ProductService productService;
@SpyBean
private ProductRepository productRepository;
@Test
void shouldCacheProductAfterFirstCall() {
// Given
Product product = Product.builder()
.id(1L)
.name("Laptop")
.price(BigDecimal.valueOf(999.99))
.stock(10)
.build();
when(productRepository.findById(1L)).thenReturn(Optional.of(product));
// When - First call
Product result1 = productService.getProductById(1L);
// Then - Verify database was called
verify(productRepository, times(1)).findById(1L);
assertThat(result1).isEqualTo(product);
// When - Second call (should hit cache)
Product result2 = productService.getProductById(1L);
// Then - Database not called again
verify(productRepository, times(1)).findById(1L); // Still 1x
assertThat(result2).isEqualTo(result1);
}
@Test
void shouldEvictCacheOnDelete() {
// Given
Product product = Product.builder()
.id(1L)
.name("Laptop")
.price(BigDecimal.valueOf(999.99))
.build();
when(productRepository.findById(1L)).thenReturn(Optional.of(product));
// Populate cache
productService.getProductById(1L);
verify(productRepository, times(1)).findById(1L);
// When - Delete (evicts cache)
productService.deleteProduct(1L);
// Then - Next call should query database again
when(productRepository.findById(1L)).thenReturn(Optional.empty());
assertThatThrownBy(() -> productService.getProductById(1L))
.isInstanceOf(ResourceNotFoundException.class);
verify(productRepository, times(2)).findById(1L);
}
}---
Example 2: Conditional Caching with Business Logic
Cache products only under specific conditions (e.g., only expensive items).
@Service
@RequiredArgsConstructor
@Slf4j
public class PremiumProductService {
private final ProductRepository productRepository;
@Cacheable(
value = "premiumProducts",
condition = "#price > 500", // Cache only items over 500
unless = "#result == null"
)
public Product getPremiumProduct(Long id, BigDecimal price) {
log.info("Fetching premium product {} (price: {})", id, price);
return productRepository.findById(id)
.orElse(null);
}
@CachePut(
value = "discountedProducts",
key = "#product.id",
condition = "#product.price < 50" // Cache only discounted items
)
public Product updateDiscountedProduct(Product product) {
log.info("Updating discounted product {}", product.getId());
return productRepository.save(product);
}
}Test:
@Test
void shouldCachePremiumProductsOnly() {
// Given - Cheap product
Product cheapProduct = Product.builder()
.id(1L)
.name("Budget Item")
.price(BigDecimal.valueOf(29.99))
.build();
// When - Call with cheap price (won't cache due to condition)
Product result = premiumProductService.getPremiumProduct(1L, BigDecimal.valueOf(29.99));
// Then - Result should be cached (condition false, so not cached)
verify(productRepository, times(1)).findById(1L);
// Second call should hit DB again
premiumProductService.getPremiumProduct(1L, BigDecimal.valueOf(29.99));
verify(productRepository, times(2)).findById(1L);
}---
Example 3: Multiple Caches and @Caching
Handle complex scenarios with multiple cache operations.
@Service
@RequiredArgsConstructor
@Slf4j
public class InventoryService {
private final ProductRepository productRepository;
@Caching(
cacheable = @Cacheable("inventoryCache"),
put = {
@CachePut(value = "stockCache", key = "#id"),
@CachePut(value = "priceCache", key = "#id")
}
)
public Product getInventoryDetails(Long id) {
log.info("Fetching inventory details for {}", id);
return productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
}
@Caching(
evict = {
@CacheEvict("inventoryCache"),
@CacheEvict("stockCache"),
@CacheEvict("priceCache")
}
)
public void reloadInventory(Long id) {
log.info("Reloading inventory for {}", id);
// Trigger inventory sync from external system
}
}---
Example 4: Programmatic Cache Management
Manually managing caches for advanced scenarios.
@Component
@RequiredArgsConstructor
@Slf4j
public class CacheManagementService {
private final CacheManager cacheManager;
public void evictProductCache(Long productId) {
Cache cache = cacheManager.getCache("products");
if (cache != null) {
cache.evict(productId);
log.info("Evicted product {} from cache", productId);
}
}
public void clearAllCaches() {
cacheManager.getCacheNames().forEach(cacheName -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
cache.clear();
log.info("Cleared cache: {}", cacheName);
}
});
}
public <T> T getOrCompute(String cacheName, Object key, Callable<T> valueLoader) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
log.warn("Cache {} not found", cacheName);
return null;
}
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper != null) {
return (T) wrapper.get();
}
try {
T value = valueLoader.call();
cache.put(key, value);
return value;
} catch (Exception e) {
log.error("Error computing cache value", e);
throw new RuntimeException(e);
}
}
}---
Example 5: Cache Warming/Preloading
Populate cache with frequently accessed data at startup.
@Component
@RequiredArgsConstructor
@Slf4j
public class CacheWarmupService implements InitializingBean {
private final ProductService productService;
private final ProductRepository productRepository;
@Override
public void afterPropertiesSet() {
warmupCache();
}
private void warmupCache() {
log.info("Warming up product cache...");
// Load top 100 products
List<Product> topProducts = productRepository.findTop100ByOrderByPopularityDesc();
topProducts.forEach(product -> {
try {
productService.getProductById(product.getId());
} catch (Exception e) {
log.warn("Failed to warm cache for product {}", product.getId(), e);
}
});
log.info("Cache warmup completed. {} products cached", topProducts.size());
}
}---
Example 6: Cache Statistics and Monitoring
Track cache performance metrics.
@Component
@RequiredArgsConstructor
@Slf4j
public class CacheStatsService {
private final CacheManager cacheManager;
@Scheduled(fixedRate = 60000) // Every minute
public void logCacheStats() {
cacheManager.getCacheNames().forEach(cacheName -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null && cache.getNativeCache() instanceof ConcurrentMapCache) {
ConcurrentMapCache concreteCache = (ConcurrentMapCache) cache.getNativeCache();
log.info("Cache [{}] - Size: {}", cacheName, concreteCache.getStore().size());
}
});
}
@GetMapping("/cache/stats")
public ResponseEntity<Map<String, CacheStats>> getCacheStatistics() {
Map<String, CacheStats> stats = new HashMap<>();
cacheManager.getCacheNames().forEach(cacheName -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
CacheStats cacheStats = new CacheStats(
cacheName,
getCacheSize(cache),
LocalDateTime.now()
);
stats.put(cacheName, cacheStats);
}
});
return ResponseEntity.ok(stats);
}
private int getCacheSize(Cache cache) {
if (cache.getNativeCache() instanceof ConcurrentMap) {
return ((ConcurrentMap<?, ?>) cache.getNativeCache()).size();
}
return 0;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class CacheStats {
private String cacheName;
private int size;
private LocalDateTime timestamp;
}---
Example 7: TTL-Based Cache with Scheduled Eviction
Expire cache entries after a specific time.
@Configuration
@EnableCaching
@EnableScheduling
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("products", "users", "orders");
}
}
@Component
@RequiredArgsConstructor
@Slf4j
public class CacheExpirationService {
private final CacheManager cacheManager;
private final Map<String, LocalDateTime> cacheExpirations = new ConcurrentHashMap<>();
public void setExpiration(String cacheName, Object key, Duration duration) {
String expirationKey = cacheName + ":" + key;
cacheExpirations.put(expirationKey, LocalDateTime.now().plus(duration));
log.info("Set cache expiration for {} after {}", expirationKey, duration);
}
@Scheduled(fixedRate = 5000) // Check every 5 seconds
public void evictExpiredEntries() {
LocalDateTime now = LocalDateTime.now();
cacheExpirations.entrySet()
.removeIf(entry -> {
if (now.isAfter(entry.getValue())) {
String[] parts = entry.getKey().split(":");
String cacheName = parts[0];
String key = parts[1];
Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
cache.evict(key);
log.info("Evicted expired cache entry: {}", entry.getKey());
}
return true;
}
return false;
});
}
}---
Example 8: Cache Invalidation Pattern with Events
Use domain events to invalidate cache across services.
public class ProductUpdatedEvent extends ApplicationEvent {
private final Long productId;
private final String changeType; // UPDATED, DELETED, CREATED
public ProductUpdatedEvent(Object source, Long productId, String changeType) {
super(source);
this.productId = productId;
this.changeType = changeType;
}
}
@Component
@RequiredArgsConstructor
@Slf4j
public class ProductService {
private final ProductRepository productRepository;
private final ApplicationEventPublisher eventPublisher;
public Product updateProduct(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
product.setName(request.getName());
product.setPrice(request.getPrice());
Product updated = productRepository.save(product);
// Publish event to invalidate cache
eventPublisher.publishEvent(new ProductUpdatedEvent(this, id, "UPDATED"));
return updated;
}
}
@Component
@RequiredArgsConstructor
@Slf4j
public class CacheInvalidationListener {
private final CacheManager cacheManager;
@EventListener
public void onProductUpdated(ProductUpdatedEvent event) {
log.info("Invalidating cache for product {}", event.getProductId());
Cache productsCache = cacheManager.getCache("products");
if (productsCache != null) {
productsCache.evict(event.getProductId());
}
Cache productsListCache = cacheManager.getCache("productsList");
if (productsListCache != null) {
productsListCache.clear();
}
}
}---
Example 9: Distributed Caching with Caffeine
Using Caffeine for local caching with advanced features.
@Configuration
@EnableCaching
public class CaffeineCacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("products", "users");
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats());
return cacheManager;
}
}
@Component
@RequiredArgsConstructor
public class CacheMetricsService {
private final CacheManager cacheManager;
@GetMapping("/cache/metrics")
public ResponseEntity<Map<String, Object>> getCacheMetrics() {
Map<String, Object> metrics = new HashMap<>();
cacheManager.getCacheNames().forEach(cacheName -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null && cache.getNativeCache() instanceof com.github.benmanes.caffeine.cache.Cache) {
com.github.benmanes.caffeine.cache.Cache<?, ?> caffeineCache =
(com.github.benmanes.caffeine.cache.Cache<?, ?>) cache.getNativeCache();
com.github.benmanes.caffeine.cache.stats.CacheStats stats = caffeineCache.stats();
metrics.put(cacheName, Map.of(
"hitCount", stats.hitCount(),
"missCount", stats.missCount(),
"hitRate", stats.hitRate(),
"size", caffeineCache.estimatedSize()
));
}
});
return ResponseEntity.ok(metrics);
}
}---
Example 10: Testing Cache-Related Scenarios
@SpringBootTest
class CacheIntegrationTest {
@Autowired
private ProductService productService;
@Autowired
private CacheManager cacheManager;
@MockBean
private ProductRepository productRepository;
@Test
void shouldDemonstrateCachingLifecycle() {
// Given
Product product = Product.builder()
.id(1L)
.name("Test Product")
.price(BigDecimal.TEN)
.build();
when(productRepository.findById(1L)).thenReturn(Optional.of(product));
// Verify cache is empty
Cache cache = cacheManager.getCache("products");
assertThat(cache.get(1L)).isNull();
// First call - populates cache
Product result1 = productService.getProductById(1L);
verify(productRepository, times(1)).findById(1L);
// Cache is now populated
assertThat(cache.get(1L)).isNotNull();
// Second call - uses cache
Product result2 = productService.getProductById(1L);
verify(productRepository, times(1)).findById(1L); // Still 1x
assertThat(result1).isEqualTo(result2);
// Manual eviction
cache.evict(1L);
assertThat(cache.get(1L)).isNull();
// Next call queries database again
Product result3 = productService.getProductById(1L);
verify(productRepository, times(2)).findById(1L);
}
}The Spring Framework provides support for transparently adding caching to an application. At its core, the abstraction applies caching to methods, thus reducing the number of executions based on the information available in the cache. The caching logic is applied transparently, without any interference to the invoker. Spring Boot auto-configures the cache infrastructure as long as caching support is enabled by using the org.springframework.cache.annotation.EnableCaching[format=annotation] annotation.
[!NOTE]
Check the {url-spring-framework-docs}/integration/cache.html[relevant
section] of the Spring Framework reference for more details.
In a nutshell, to add caching to an operation of your service add the relevant annotation to its method, as shown in the following example:
include-code::MyMathService[]
This example demonstrates the use of caching on a potentially costly operation. Before invoking computePiDecimal, the abstraction looks for an entry in the piDecimals cache that matches the precision argument. If an entry is found, the content in the cache is immediately returned to the caller, and the method is not invoked. Otherwise, the method is invoked, and the cache is updated before returning the value.
[!CAUTION]
You can also use the standard JSR-107 (JCache) annotations (such as
javax.cache.annotation.CacheResult[format=annotation])transparently. However, we strongly advise you to not mix and match
the Spring Cache and JCache annotations.
If you do not add any specific cache library, Spring Boot auto-configures a simple provider that uses concurrent maps in memory. When a cache is required (such as piDecimals in the preceding example), this provider creates it for you. The simple provider is not really recommended for production usage, but it is great for getting started and making sure that you understand the features. When you have made up your mind about the cache provider to use, please make sure to read its documentation to figure out how to configure the caches that your application uses. Nearly all providers require you to explicitly configure every cache that you use in the application. Some offer a way to customize the default caches defined by the configprop:spring.cache.cache-names[] property.
[!TIP]
It is also possible to transparently
{url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-put[update]
or
{url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-evict[evict]
data from the cache.
Supported Cache Providers
The cache abstraction does not provide an actual store and relies on abstraction materialized by the org.springframework.cache.Cache[] and org.springframework.cache.CacheManager[] interfaces.
If you have not defined a bean of type org.springframework.cache.CacheManager[] or a org.springframework.cache.interceptor.CacheResolver[] named cacheResolver (see `org.springframework.cache.annotation.CachingConfigurer[]), Spring Boot tries to detect the following providers (in the indicated order):
1. io/caching.xml#io.caching.provider.generic
2. io/caching.xml#io.caching.provider.jcache (EhCache 3, Hazelcast, Infinispan, and others)
3. io/caching.xml#io.caching.provider.hazelcast
4. io/caching.xml#io.caching.provider.infinispan
5. io/caching.xml#io.caching.provider.couchbase
6. io/caching.xml#io.caching.provider.redis
7. io/caching.xml#io.caching.provider.caffeine
8. io/caching.xml#io.caching.provider.cache2k
9. io/caching.xml#io.caching.provider.simple
Additionally, {url-spring-boot-for-apache-geode-site}[Spring Boot for Apache Geode] provides {url-spring-boot-for-apache-geode-docs}#geode-caching-provider[auto-configuration for using Apache Geode as a cache provider].
[!TIP]
If the `org.springframework.cache.CacheManager[] is
auto-configured by Spring Boot, it is possible to force a particular
cache provider by setting the configprop:spring.cache.type[]
property. Use this property if you need to use no-op
caches in certain
environments (such as tests).
[!TIP]
Use the spring-boot-starter-cache starter to quickly add basiccaching dependencies. The starter brings in spring-context-support.If you add dependencies manually, you must include
spring-context-support in order to use the JCache or Caffeinesupport.
If the org.springframework.cache.CacheManager[] is auto-configured by Spring Boot, you can further tune its configuration before it is fully initialized by exposing a bean that implements the org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer[] interface. The following example sets a flag to say that null values should not be passed down to the underlying map:
include-code::MyCacheManagerConfiguration[]
[!NOTE]
In the preceding example, an auto-configured
`org.springframework.cache.concurrent.ConcurrentMapCacheManager[]
is expected. If that is not the case (either you provided your own
config or a different cache provider was auto-configured), the
customizer is not invoked at all. You can have as many customizers as
you want, and you can also order them by using
org.springframework.core.annotation.Order[format=annotation]or `org.springframework.core.Ordered[].
Generic
Generic caching is used if the context defines at least one org.springframework.cache.Cache[] bean. A org.springframework.cache.CacheManager[] wrapping all beans of that type is created.
JCache (JSR-107)
JCache is bootstrapped through the presence of a javax.cache.spi.CachingProvider[] on the classpath (that is, a JSR-107 compliant caching library exists on the classpath), and the org.springframework.cache.jcache.JCacheCacheManager[] is provided by the spring-boot-starter-cache starter. Various compliant libraries are available, and Spring Boot provides dependency management for Ehcache 3, Hazelcast, and Infinispan. Any other compliant library can be added as well.
It might happen that more than one provider is present, in which case the provider must be explicitly specified. Even if the JSR-107 standard does not enforce a standardized way to define the location of the configuration file, Spring Boot does its best to accommodate setting a cache with implementation details, as shown in the following example:
Only necessary if more than one provider is present
spring: cache: jcache: provider: "com.example.MyCachingProvider" config: "classpath:example.xml"
[!NOTE]
When a cache library offers both a native implementation and JSR-107
support, Spring Boot prefers the JSR-107 support, so that the same
features are available if you switch to a different JSR-107
implementation.
[!TIP]
Spring Boot has general support for Hazelcast. If
a single `com.hazelcast.core.HazelcastInstance[] is
available, it is automatically reused for the
`javax.cache.CacheManager[] as well, unless the
configprop:spring.cache.jcache.config[] property is specified.
There are two ways to customize the underlying `javax.cache.CacheManager[]:
- Caches can be created on startup by setting the
configprop:spring.cache.cache-names[] property. If a custom `javax.cache.configuration.Configuration[] bean is defined, it is used to customize them.
- `org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer[]
beans are invoked with the reference of the `javax.cache.CacheManager[] for full customization.
[!TIP]
If a standard `javax.cache.CacheManager[] bean is defined, it
is wrapped automatically in an
`org.springframework.cache.CacheManager[] implementation that
the abstraction expects. No further customization is applied to it.
Hazelcast
Spring Boot has general support for Hazelcast. If a com.hazelcast.core.HazelcastInstance[] has been auto-configured and com.hazelcast:hazelcast-spring is on the classpath, it is automatically wrapped in a org.springframework.cache.CacheManager[].
[!NOTE]
Hazelcast can be used as a JCache compliant cache or as a Spring
`org.springframework.cache.CacheManager[] compliant cache.
When setting configprop:spring.cache.type[] to hazelcast, SpringBoot will use the `org.springframework.cache.CacheManager[]
based implementation. If you want to use Hazelcast as a JCache
compliant cache, set configprop:spring.cache.type[] to jcache. Ifyou have multiple JCache compliant cache providers and want to force
the use of Hazelcast, you have to explicitly set the JCache
provider.
Infinispan
Infinispan has no default configuration file location, so it must be specified explicitly. Otherwise, the default bootstrap is used.
spring: cache: infinispan: config: "infinispan.xml"
Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property. If a custom `org.infinispan.configuration.cache.ConfigurationBuilder[] bean is defined, it is used to customize the caches.
To be compatible with Spring Boot’s Jakarta EE 9 baseline, Infinispan’s -jakarta modules must be used. For every module with a -jakarta variant, the variant must be used in place of the standard module. For example, infinispan-core-jakarta and infinispan-commons-jakarta must be used in place of infinispan-core and infinispan-commons respectively.
Couchbase
If Spring Data Couchbase is available and Couchbase is configured, a org.springframework.data.couchbase.cache.CouchbaseCacheManager[] is auto-configured. It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using spring.cache.couchbase.` properties. For instance, the following configuration creates `cache1` and `cache2` caches with an entry expiration* of 10 minutes:
spring: cache: cache-names: "cache1,cache2" couchbase: expiration: "10m"
If you need more control over the configuration, consider registering a org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer[] bean. The following example shows a customizer that configures a specific entry expiration for cache1 and cache2`:
include-code::MyCouchbaseCacheManagerConfiguration[]
Redis
If Redis is available and configured, a org.springframework.data.redis.cache.RedisCacheManager[] is auto-configured. It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using spring.cache.redis.` properties. For instance, the following configuration creates `cache1` and `cache2` caches with a time to live* of 10 minutes:
spring: cache: cache-names: "cache1,cache2" redis: time-to-live: "10m"
[!NOTE]
By default, a key prefix is added so that, if two separate caches use
the same key, Redis does not have overlapping keys and cannot return
invalid values. We strongly recommend keeping this setting enabled if
you create your own
`org.springframework.data.redis.cache.RedisCacheManager[].
[!TIP]
You can take full control of the default configuration by adding a
`org.springframework.data.redis.cache.RedisCacheConfiguration[]
org.springframework.context.annotation.Bean[format=annotation]of your own. This can be useful if you need to customize the default
serialization strategy.
If you need more control over the configuration, consider registering a org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer[] bean. The following example shows a customizer that configures a specific time to live for cache1 and cache2`:
include-code::MyRedisCacheManagerConfiguration[]
Caffeine
Caffeine is a Java 8 rewrite of Guava’s cache that supersedes support for Guava. If Caffeine is present, a org.springframework.cache.caffeine.CaffeineCacheManager[] (provided by the spring-boot-starter-cache` starter) is auto-configured. Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property and can be customized by one of the following (in the indicated order):
1. A cache spec defined by spring.cache.caffeine.spec
2. A `com.github.benmanes.caffeine.cache.CaffeineSpec[] bean is defined
3. A `com.github.benmanes.caffeine.cache.Caffeine[] bean is defined
For instance, the following configuration creates cache1 and cache2 caches with a maximum size of 500 and a time to live of 10 minutes
spring: cache: cache-names: "cache1,cache2" caffeine: spec: "maximumSize=500,expireAfterAccess=600s"
If a com.github.benmanes.caffeine.cache.CacheLoader[] bean is defined, it is automatically associated to the org.springframework.cache.caffeine.CaffeineCacheManager[]. Since the com.github.benmanes.caffeine.cache.CacheLoader[] is going to be associated with *all* caches managed by the cache manager, it must be defined as CacheLoader<Object, Object>`. The auto-configuration ignores any other generic type.
Cache2k
Cache2k is an in-memory cache. If the Cache2k spring integration is present, a SpringCache2kCacheManager is auto-configured.
Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property. Cache defaults can be customized using a `org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer[] bean. The following example shows a customizer that configures the capacity of the cache to 200 entries, with an expiration of 5 minutes:
include-code::MyCache2kDefaultsConfiguration[]
Simple
If none of the other providers can be found, a simple implementation using a java.util.concurrent.ConcurrentHashMap[] as the cache store is configured. This is the default if no caching library is present in your application. By default, caches are created as needed, but you can restrict the list of available caches by setting the cache-names property. For instance, if you want only cache1 and cache2 caches, set the cache-names` property as follows:
spring: cache: cache-names: "cache1,cache2"
If you do so and your application uses a cache not listed, then it fails at runtime when the cache is needed, but not on startup. This is similar to the way the "real" cache providers behave if you use an undeclared cache.
None
When org.springframework.cache.annotation.EnableCaching[format=annotation] is present in your configuration, a suitable cache configuration is expected as well. If you have a custom org.springframework.cache.CacheManager, consider defining it in a separate org.springframework.context.annotation.Configuration[format=annotation] class so that you can override it if necessary. None uses a no-op implementation that is useful in tests, and slice tests use that by default via org.springframework.boot.test.autoconfigure.core.AutoConfigureCache[format=annotation].
If you need to use a no-op cache rather than the auto-configured cache manager in a certain environment, set the cache type to none, as shown in the following example:
spring: cache: type: "none"
Spring Framework Cache Reference (Official)
Curated excerpts from the official Spring Framework reference documentation covering caching fundamentals and annotation usage. Source pages are from the Spring Framework Reference Guide 6.2.
Cache Abstraction Overview
- Purpose: Transparently wrap expensive service methods and reuse results
resolved from configured cache managers.
- Enablement:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("books");
}
}Source: /integration/cache/annotations
- Supported return types:
CompletableFuture, ReactorMono/Flux,
blocking objects, and collections are all cacheable. For async/reactive types, Spring stores the resolved value and rehydrates it on retrieval.
Core Annotations
@Cacheable
- Cache the method invocation result using the provided cache name and key.
- Supports conditional caching with
condition(pre-invocation) andunless
(post-invocation, access #result).
@Cacheable(cacheNames = "book", condition = "#isbn.length() == 13", unless = "#result.hardback")
public Book findBook(String isbn) { ... }Source: /integration/cache/annotations
@CachePut and @CacheEvict
@CachePut: Always run the method and update cache entry with fresh result.@CacheEvict: Remove entries; useallEntries = trueorbeforeInvocation
for pre-call eviction.
@CacheEvict(cacheNames = "books", key = "#isbn", beforeInvocation = true)
public void reset(String isbn) { ... }Source: /integration/cache/annotations
@Caching
- Bundle multiple cache operations on a single method:
@Caching(evict = {
@CacheEvict("primary"),
@CacheEvict(cacheNames = "secondary", key = "#isbn")
})
public Book importBooks(String isbn) { ... }Source: /integration/cache/annotations
Store Configuration Highlights
- Caffeine: Configure
CaffeineCacheManagerto create caches on demand.
@Bean
CacheManager cacheManager() {
return new CaffeineCacheManager();
}Source: /integration/cache/store-configuration
- XML alternative: Use
<cache:annotation-driven cache-manager="..."/>
when annotation configuration is not feasible.
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/>Source: /integration/cache/declarative-xml
Reactive and Async Support
@Cacheableworks with asynchronous signatures:
@Cacheable("books")
public Mono<Book> findBook(ISBN isbn) { ... } @Cacheable(cacheNames = "foos", sync = true)
public CompletableFuture<Foo> executeExpensiveOperation(String id) { ... }Source: /integration/cache/annotations
Additional Resources
- `spring-cache-doc-snippet.md`: Excerpt of the
narrative caching overview from the Spring documentation.
- Refer to `cache-core-reference.md` for expanded
API reference material and cache-examples.md for progressive examples.
Related skills
Forks & variants (1)
Spring Boot Cache has 1 known copy in the catalog totaling 21 installs. They canonicalize to this original listing.
- giuseppe-trisciuoglio - 21 installs
How it compares
Use this reference skill for Spring-native cache abstraction choices instead of generic caching tutorials that skip CacheManager tradeoffs.
FAQ
What does spring boot cache do?
Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cach
When should I invoke spring boot cache?
Provides patterns for implementing Spring Boot caching: configures Redis/Caffeine/EhCache providers with TTL and eviction policies, applies @Cacheable/@CacheEvict/@CachePut annotations, validates cach
What are key capabilities?
Add `@Cacheable`, `@CachePut`, or `@CacheEvict` to service methods.
Is Spring Boot Cache safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.