Reputation: 2251
I have a Spring Boot/MVC app that should store some Simple POJOs sent from users for 15 minutes of time. When this time expires, this object should be removed from ConcurrentHashMap
. At first ConcurrentHashMap
was something I wanted to implement this feature with, but then I thought maybe leveraging Guava's cache would be a better option, since it has a time-based eviction out of the box.
My service implementation
@CachePut(cacheNames = "teamConfigs", key = "#authAccessDto.accessToken")
@Override
public OAuthAccessDto saveConfig(OAuthAccessDto authAccessDto) {
return authAccessDto;
}
@Override
@Cacheable(cacheNames = "teamConfigs")
public OAuthAccessDto getConfig(String accessToken) {
// we assume that the cache is already populated
return null;
}
As you can see, we save data with saveConfig
and then when we need to retrieve it, we call getConfig
.
Cache configuration in Spring boot is the following (yml file):
spring:
cache:
cache-names: teamConfigs
guava:
spec: expireAfterWrites=900s
However, after reading Guava's cache doc https://github.com/google/guava/wiki/CachesExplained I found that Guava can clean up caches even before the time defined in expireAfterWrites
elapses (and even before it runs out of memory).
How can I configure Guava Cache to keep objects until the time expires (considering it did not run out of memory). Maybe I should opt for some other solution?
Upvotes: 0
Views: 1570
Reputation: 33121
I don't know about Guava but you could use any JSR-107 compliant provider and a simple configuration that would look like this:
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
cm.createCache("teamConfigs", new MutableConfiguration<>()
.setExpiryPolicyFactory(CreatedExpiryPolicy
.factoryOf(new Duration(MINUTES, 15)));
};
}
Caffeine (a rewrite of Guava with Java8) has a JSR-107 provider so you could use that. Maybe that version does not exhibit what you experience with Guava? If so, support is expected in Spring Boot 1.4 but you can give the JSR-107 support a try right now.
If you don't want to use that, you could give expiringmap a try. It does not have any Cache
implementation in the Spring abstraction but since it's a Map
you can easily wrap it, something like on the top of my head:
@Bean
public Cache teamConfigsCache() {
Map<Object, Object> map = ExpiringMap.builder()
.expiration(15, TimeUnit.MINUTES)
.build();
return new ConcurrentMapCache("teamConfigs", map , true);
}
If Spring Boot discovers at least a Cache
bean in your configuration, it auto-creates a CacheManager
implementation that wraps them. You can force that behaviour via the spring.cache.type
property.
Upvotes: 2