package com.example.demo.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("users", "posts");
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000)
.recordStats());
return cacheManager;
}
}
package com.example.demo.service;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@CacheConfig(cacheNames = "users")
public class CachedUserService {
private final UserRepository userRepository;
public CachedUserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Cacheable(key = "#id")
public Optional<User> findById(Long id) {
System.out.println("Fetching user from database: " + id);
return userRepository.findById(id);
}
@Cacheable(key = "#email")
public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email);
}
@Cacheable
public List<User> findAll() {
return userRepository.findAll();
}
@CachePut(key = "#user.id")
public User save(User user) {
return userRepository.save(user);
}
@Caching(evict = {
@CacheEvict(key = "#id"),
@CacheEvict(allEntries = true, cacheNames = "users")
})
public void deleteById(Long id) {
userRepository.deleteById(id);
}
@CacheEvict(allEntries = true)
public void clearCache() {
System.out.println("Clearing all user cache");
}
@Cacheable(key = "#query", condition = "#query.length() > 3")
public List<User> search(String query) {
return userRepository.findByNameContainingIgnoreCase(query);
}
@Cacheable(key = "#id", unless = "#result == null")
public User findActiveUser(Long id) {
return userRepository.findById(id)
.filter(User::isActive)
.orElse(null);
}
}
Spring Cache abstraction simplifies caching with annotations. @Cacheable caches method results—subsequent calls with same arguments return cached values. @CachePut always executes methods and updates cache. @CacheEvict removes entries or clears entire caches. Cache providers include Caffeine, Redis, Ehcache, or simple in-memory maps. @EnableCaching activates caching infrastructure. Cache names organize data by domain. Condition and unless parameters provide fine-grained control. KeyGenerator customizes cache keys. Caching dramatically improves performance for expensive operations—database queries, API calls, calculations. Time-to-live (TTL) prevents stale data. Redis enables distributed caching across service instances. Proper caching balances performance gains against data freshness requirements.