Spring Cache

SkillDatabases & data

Spring Cache abstraction for Spring Boot 3.x. Covers @Cacheable, @CacheEvict, @CachePut, cache managers (Caffeine, Redis, EhCache), TTL configuration, cache keys, conditional caching, and cache synchronization.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Spring Cache skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/spring-cache/SKILL.md and read by ahel’s review.

Quick Start

@SpringBootApplication
@EnableCaching
public class Application {}

@Service
public class UserService {

    @Cacheable("users")
    public User findById(Long id) {
        return userRepository.findById(id).orElseThrow();
    }

    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}
spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=10m

Cache Annotations

@Cacheable

@Cacheable("products")
public Product findById(Long id) { }

@Cacheable(value = "products", key = "#category + '-' + #status")
public List<Product> findByCategoryAndStatus(String category, String status) { }

@Cacheable(value = "products", condition = "#id > 0")
public Product findByIdConditional(Long id) { }

@Cacheable(value = "products", unless = "#result == null")
public Product findByIdUnlessNull(Long id) { }

@Cacheable(value = "products", sync = true)  // One thread populates
public Product findByIdSync(Long id) { }

@CacheEvict

@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) { }

@CacheEvict(value = "products", allEntries = true)
public void clearProductCache() { }

@CacheEvict(value = "products", key = "#id", beforeInvocation = true)
public void deleteProductBeforeInvocation(Long id) { }

@CachePut

@CachePut(value = "products", key = "#product.id")
public Product saveProduct(Product product) {
    return productRepository.save(product);
}

@CachePut(value = "products", key = "#result.id")
public Product createProduct(CreateProductRequest request) {
    return productRepository.save(new Product(request));
}

@Caching (Multiple Operations)

@Caching(
    put = {
        @CachePut(value = "products", key = "#result.id"),
        @CachePut(value = "productsBySku", key = "#result.sku")
    },
    evict = {
        @CacheEvict(value = "productList", allEntries = true)
    }
)
public Product createProduct(CreateProductRequest request) { }

@CacheConfig (Class-Level)

@Service
@CacheConfig(cacheNames = "products", keyGenerator = "customKeyGenerator")
public class ProductService {

    @Cacheable  // Uses class config
    public Product findById(Long id) { }

    @Cacheable(cacheNames = "inventory")  // Override cache name
    public Inventory getInventory(Long productId) { }
}

Full Reference: See managers.md for Caffeine, Redis, EhCache configurations.


Quick Cache Manager Setup

Caffeine (Single Instance)

@Bean
public CacheManager cacheManager() {
    CaffeineCacheManager manager = new CaffeineCacheManager();
    manager.setCaffeine(Caffeine.newBuilder()
        .maximumSize(10_000)
        .expireAfterWrite(Duration.ofMinutes(10))
        .recordStats());
    return manager;
}

Redis (Distributed)

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Duration.ofMinutes(10))
        .serializeValuesWith(SerializationPair
            .fromSerializer(new GenericJackson2JsonRedisSerializer()));

    return RedisCacheManager.builder(factory)
        .cacheDefaults(config)
        .build();
}

Full Reference: See advanced.md for Multi-Level Caching, Metrics, Synchronization.


Best Practices

DoDon't
Use Caffeine for single-instanceSkip TTL configuration
Use Redis for distributedCache mutable objects
Configure TTL alwaysIgnore cache eviction
Use sync=true for expensive opsUse high cardinality keys
Implement cache metricsCache sensitive data unencrypted

Production Checklist

  • Cache provider configured (Caffeine/Redis)
  • TTL configured for every cache
  • Cache eviction on write operations
  • Metrics configured
  • Serialization tested
  • Distributed lock for critical ops

When NOT to Use This Skill

  • Distributed caching - Use spring-data-redis
  • Redis operations - Use redis skill
  • Session storage - Use Spring Session

Common Pitfalls

ErrorCauseSolution
Cache not workingInternal call (same bean)Use self-injection
Null pointerNull values cachedUse unless = "#result == null"
Memory leakTTL not configuredSet expireAfterWrite
Serialization errorNon-serializable objectsImplement Serializable

Anti-Patterns

Anti-PatternProblemSolution
Caching mutable objectsStale dataCache immutable data
No TTL configuredStale cache foreverSet expireAfterWrite
@Cacheable on voidNo effectOnly cache with return
No cache syncRace conditionsUse sync=true or locks

Quick Troubleshooting

ProblemDiagnosticFix
Cache not workingCheck @EnableCachingAdd annotation
Wrong data cachedCheck cache keyDefine explicit key
Cache not evictedCheck key expressionVerify key matches
Self-invocation bypassSame class callInject self

Reference Files

FileContent
managers.mdCaffeine, Redis, EhCache, Key Generators
advanced.mdMulti-Level, Metrics, Sync, Testing

External Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
spring-cache
Source
github.com/claude-dev-suite/claude-dev-suite