I have implemented a cache and now I want to add an expiry time.
How can I set an expiry time in spring boot with @Cacheable
?
This is a code snippet:
@Cacheable(value="forecast",unless="#result == null")
I have implemented a cache and now I want to add an expiry time.
How can I set an expiry time in spring boot with @Cacheable
?
This is a code snippet:
@Cacheable(value="forecast",unless="#result == null")
I use life hacking like this:
@Configuration
@EnableCaching
@EnableScheduling
public class CachingConfig {
public static final String GAMES = "GAMES";
@Bean
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(GAMES);
return cacheManager;
}
@CacheEvict(allEntries = true, value = {GAMES})
@Scheduled(fixedDelay = 10 * 60 * 1000 , initialDelay = 500)
public void reportCacheEvict() {
System.out.println("Flush Cache " + dateFormat.format(new Date()));
}
}
Note that this answer uses ehcache, which is one of supported Spring Boot cache managers, and arguably one of the most popular.
First you need to add to pom.xml
:
<!-- Spring Framework Caching Support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
In src/main/resources/ehcache.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<defaultCache eternal="true" maxElementsInMemory="100" overflowToDisk="false" />
<cache name="forecast"
maxElementsInMemory="1000"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
From the reference documentation
Directly through your cache provider. The cache abstraction is… well, an abstraction not a cache implementation. The solution you are using might support various data policies and different topologies which other solutions do not (take for example the JDK ConcurrentHashMap) - exposing that in the cache abstraction would be useless simply because there would no backing support. Such functionality should be controlled directly through the backing cache, when configuring it or through its native API.
You cannot specify expiry time with @cacheable notation, since @cacheable does not provide any such configurable option.
However different caching vendors providing spring caching have provided this feature through their own configurations. For example NCache / TayzGrid allows you to create different cache regions with configurable expiration time.
If you have implemented your own cache, you will need to define a way to specify expiration in you cache provider and will also need to incorporate expiration logic in your solution.
I use caffeine-caching, with this configuration for a 60 minute expiration:
spring.cache.cache-names=forecast
spring.cache.caffeine.spec=expireAfterWrite=60m
hibernate.cache.region.factory_class
in spring.properties
–
Biophysics You can achieve this kind of eviction strategy by making use of @Scheduled
annotation. It is possible to schedule with a fixedRate or even with a cron expression.
@Autowired
CacheManager cacheManager;
public void evictAllCaches() {
cacheManager.getCacheNames().stream()
.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
}
@Scheduled(fixedRate = 6000)
public void evictAllcachesAtIntervals() {
evictAllCaches();
}
Found this Spring cache: Set expiry time to a cache entry.
It uses the spring-boot-starter-cache
dependency and works as expected . You can configure the expiry time for cached objects as well as the max number of cached values.
If you are using Caffeine than you can add the following line in your application.properties
file:
spring.cache.caffeine.spec=expireAfterAccess=300s
hibernate.cache.region.factory_class
in spring.properties
–
Biophysics You can solve it with a LocalDateTime
object. For example:
@Cacheable(value="forecast", key = "#date.toString()")
public void forecast(LocalDate date){
//
}
public void call(){
forecast(LocalDate.now());
}
Cache will expire after 1 day.
Positive aspect - it does not require a scheduled job.
Negative aspect - old data remains cached.
@Cacheable
does not support expire time. But if you are using redis then you can use time-to-live
and set the time.
For example :
spring.cache.redis.time-to-live=60m
I ran into this and needed a way for volume public traffic to get cached content fast, and not cause a big buildup with cache eviction. I created two entry points to the service method that fetches the data, as so:
@Cacheable(value="document")
public Document findByIdCacheable(Integer id) throws ResourceNotFoundException {
return fetchDocument(id);
}
@CachePut(value="document")
public Document findById(Integer id) throws ResourceNotFoundException {
return fetchDocument(id, versionId, privileged);
}
@Transactional(readOnly=true)
private Document fetchDocument(Integer id) throws ResourceNotFoundException {
... perform the work here
}
You can then provide a scheduled task to call the method with the @CachePut annotation on a periodic basis to update the cache entry without evicting it. Under heavy front end load from the public, I find that evicting cache entries can cause, under some implementations, a massive queue up of incoming transaction threads if the back end of the service takes more than a few seconds to build the entry. I find this can help prevent that, as well as provide an entry point to bypass cache by a controller method for administrative purposes.
© 2022 - 2024 — McMap. All rights reserved.