@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager manager = new SimpleCacheManager();
manager.setCaches(Arrays.asList(
new ConcurrentMapCache("users"),
new ConcurrentMapCache("orders"),
new ConcurrentMapCache("products")
));
return manager;
}
// Or use ConcurrentMapCacheManager
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users", "orders");
}
}@Service
public class UserService {
// Cache with key = id
@Cacheable("users")
public User getUser(Long id) {
return database.findUser(id);
}
// Custom key with SpEL
@Cacheable(value = "users", key = "#username")
public User findByUsername(String username) {
return database.findByUsername(username);
}
// Composite key
@Cacheable(value = "searches", key = "{#criteria, #page, #size}")
public Page<User> search(SearchCriteria criteria, int page, int size) {
return database.search(criteria, page, size);
}
// Conditional caching
@Cacheable(value = "users", condition = "#id > 0")
public User getUserConditional(Long id) {
return database.findUser(id);
}
// Unless (skip caching if result matches condition)
@Cacheable(value = "users", unless = "#result == null")
public User getUserUnlessNull(Long id) {
return database.findUser(id);
}
// Sync for single-flight pattern
@Cacheable(value = "expensive", sync = true)
public ExpensiveResult expensiveOperation(String param) {
return compute(param);
}
// Custom key generator
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")
public User customKey(String username, String tenant) {
return database.find(username, tenant);
}
}@Service
public class UserService {
// Update cache after method execution
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return database.update(user);
}
// Conditional update
@CachePut(value = "users", key = "#result.id", condition = "#result.active")
public User saveUser(User user) {
return database.save(user);
}
}@Service
public class UserService {
// Evict single entry
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
database.delete(id);
}
// Evict all entries
@CacheEvict(value = "users", allEntries = true)
public void deleteAllUsers() {
database.deleteAll();
}
// Evict before method execution
@CacheEvict(value = "users", beforeInvocation = true)
public void clearCache() {
// Cache cleared even if method throws exception
}
// Evict multiple caches
@CacheEvict(value = {"users", "userStats"}, key = "#id")
public void removeUserData(Long id) {
database.delete(id);
}
}@Service
public class UserService {
@Caching(
cacheable = {
@Cacheable(value = "users", key = "#id")
},
put = {
@CachePut(value = "userCache", key = "#result.username"),
@CachePut(value = "emailCache", key = "#result.email")
}
)
public User getUser(Long id) {
return database.findUser(id);
}
@Caching(
evict = {
@CacheEvict(value = "users", key = "#id"),
@CacheEvict(value = "userStats", allEntries = true)
}
)
public void deleteUser(Long id) {
database.delete(id);
}
}@Service
@CacheConfig(cacheNames = "users")
public class UserService {
@Cacheable // Uses "users" cache
public User getUser(Long id) {
return database.findUser(id);
}
@CacheEvict // Evicts from "users" cache
public void deleteUser(Long id) {
database.delete(id);
}
}
@Service
@CacheConfig(cacheNames = "users", keyGenerator = "customKeyGenerator")
public class UserServiceWithCustomKey {
@Cacheable
public User getUser(String username, String tenant) {
return database.find(username, tenant);
}
}@Configuration
public class CacheConfig {
@Bean("customKeyGenerator")
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder key = new StringBuilder();
key.append(target.getClass().getSimpleName());
key.append(".");
key.append(method.getName());
for (Object param : params) {
key.append(".").append(param);
}
return key.toString();
};
}
}@Configuration
public class CacheConfig {
@Bean
public CacheResolver cacheResolver(CacheManager cacheManager) {
return context -> {
Collection<String> cacheNames = new ArrayList<>();
// Dynamic cache selection based on method or parameters
String tenant = extractTenant(context);
cacheNames.add("cache-" + tenant);
return cacheNames.stream()
.map(cacheManager::getCache)
.filter(Objects::nonNull)
.collect(Collectors.toList());
};
}
}
@Service
public class MultiTenantService {
@Cacheable(cacheResolver = "cacheResolver")
public Data getData(String tenant, Long id) {
return database.find(tenant, id);
}
}// Concurrent Map (Simple)
@Bean
public CacheManager concurrentMapCacheManager() {
return new ConcurrentMapCacheManager("users", "orders");
}
// Caffeine (High-performance)
@Bean
public CacheManager caffeineCacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager("users", "orders");
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
// Composite (Multiple backends)
@Bean
public CacheManager compositeCacheManager() {
CompositeCacheManager manager = new CompositeCacheManager();
manager.setCacheManagers(Arrays.asList(
caffeineCacheManager(),
redisCacheManager()
));
manager.setFallbackToNoOpCache(true);
return manager;
}@Service
public class CacheService {
@Autowired
private CacheManager cacheManager;
public void manualCacheOperations() {
Cache cache = cacheManager.getCache("users");
// Put value
cache.put("user1", new User(1L, "John"));
// Get value
Cache.ValueWrapper wrapper = cache.get("user1");
if (wrapper != null) {
User user = (User) wrapper.get();
}
// Get with type
User user = cache.get("user1", User.class);
// Get with value loader (compute if absent)
User computed = cache.get("user1", () -> database.findUser(1L));
// Evict single entry
cache.evict("user1");
// Clear all
cache.clear();
// Atomic putIfAbsent
Cache.ValueWrapper existing = cache.putIfAbsent("user1", new User(1L, "John"));
}
}