Caching is essential for improving application performance and reducing load on external resources. Spring Boot provides several annotations to manage caching in a flexible manner.
1. Understanding the Core Annotations
1.1 @Cacheable
- Purpose: Avoids method execution if a cached result is available.
- How it works:
- Checks if the key exists in cache.
- If present, returns cached value.
- If absent, executes the method and caches the result.
- Use case: Expensive calculations, external API calls, repeated GET requests.
@Cacheable(value = "weather", key = "#zip") public int getWeather(String zip) { // Method execution occurs only if cache doesn't exist return fetchWeatherFromExternalService(zip); }
Key points:
- Skips execution whenever possible.
- Caches results for future requests.
- Ideal for GET operations where the data is mostly read-only.
1.2 @CacheEvict
- Purpose: Removes cache entries.
- When to use: During updates, deletes, or when you want to refresh cached data.
- Important property:
beforeInvocation
- If
true
, cache is cleared before method execution. - Default: false (clears cache after successful method execution).
- If
@CacheEvict(value = "weather", key = "#zip", beforeInvocation = true) public void clearWeatherCache(String zip) { // Cache will be evicted before executing this method }
Notes:
- Ensures stale data is removed.
- Critical for POST, PUT, DELETE operations where data changes.
1.3 @CachePut
- Purpose: Updates cache every time method executes.
- Difference from
@Cacheable
:- Always executes the method.
- Stores the result in cache, overwriting existing entry.
@CachePut(value = "weather", key = "#zip") public int updateWeather(String zip) { return fetchWeatherFromExternalService(zip); }
Use case:
- Hybrid approach where you want both execution and cache update.
- Useful for pre-fetching data periodically.
2. Practical Example: Weather Service with Scheduled Cache Updates
2.1 Use Case
- Application provides weather info to users.
- External API calls are slow or costly.
- Goal: Provide fast, reliable responses while keeping data reasonably fresh.
2.2 Service Layer
@Service public class WeatherService { private final ExternalWeatherService externalService; public WeatherService(ExternalWeatherService externalService) { this.externalService = externalService; } @Cacheable(value = "weather", key = "#zip") public int getWeather(String zip) { // Will be skipped if cached return 0; // Placeholder } @Scheduled(fixedRate = 10000) // Every 10 seconds @CachePut(value = "weather", key = "#zip") public int updateWeather(String zip) { // Periodically refreshes cache return externalService.fetchWeather(zip); } }
2.3 External Service Simulation
@Service public class ExternalWeatherService { public int fetchWeather(String zip) { // Simulate external API call return new Random().nextInt(100); // Random temperature } }
2.4 Controller Layer
@RestController @RequestMapping("/weather") public class WeatherController { private final WeatherService weatherService; public WeatherController(WeatherService weatherService) { this.weatherService = weatherService; } @GetMapping("/{zip}") public int getWeather(@PathVariable String zip) { return weatherService.getWeather(zip); } }
Behavior:
- First request for a ZIP code executes
getWeather()
(returns cached value after first call). - Subsequent requests return cached results immediately.
- Scheduled method
updateWeather()
updates the cache every 10 seconds, ensuring fresh data without impacting users.
3. Advantages
- Performance improvement: Users always get fast responses from cache.
- Reduced API costs: Fewer calls to external services.
- Controlled freshness: Scheduled updates ensure data is reasonably current.
- Flexible eviction:
@CacheEvict
ensures stale data is removed when necessary.
4. Limitations
- By default,
@Cacheable
doesn’t support automatic expiry. Redis TTL can be configured for this. - Limited flexibility for reactive streams and publisher types.
- Full support for reactive programming may require additional utilities or custom implementations.
5. Real-World Analogy
- Twitter feed, Netflix recommendations, or weather apps:
- Cached results provide instant response.
- Background services periodically update the cache.
- Users experience consistent, fast performance without waiting for expensive computations.
This approach demonstrates a robust caching strategy combining @Cacheable
, @CachePut
, @CacheEvict
, and scheduled updates for efficient, high-performance applications.