Puis-je définir un TTL pour @Cacheable
J'essaie le support d'annotation @Cacheable
pour Spring 3.1 et je me demande s'il existe un moyen de faire effacer les données mises en cache après un certain temps en définissant un TTL?
En ce moment, d'après ce que je peux voir, je dois l'effacer moi-même en utilisant le @CacheEvict
, et en l'utilisant avec @Scheduled
je peux faire une implémentation TTL moi-même mais cela semble un peu pour une tâche aussi simple?
8 réponses
Comment puis-je définir la fonctionnalité TTL/TTI/Eviction policy/XXX?
Directement via votre fournisseur de cache. L'abstraction du cache est... Eh bien, une abstraction pas une implémentation de cache
Donc, si vous utilisez EHCache, utilisez la configuration de EHCache pour configurer le TTL.
Vous pouvez également utiliser des goyaves CacheBuilder pour construire un cache, et passer la vue ConcurrentMap de ce cache à la méthode setStore du ConcurrentMapCacheFactoryBean.
Printemps 3.1 et Goyave 1.13.1:
@EnableCaching
@Configuration
public class CacheConfiguration implements CachingConfigurer {
@Override
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager() {
@Override
protected Cache createConcurrentMapCache(final String name) {
return new ConcurrentMapCache(name,
CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).maximumSize(100).build().asMap(), false);
}
};
return cacheManager;
}
@Override
public KeyGenerator keyGenerator() {
return new DefaultKeyGenerator();
}
}
Voici un exemple complet de configuration du Cache Goyave au printemps. J'ai utilisé la goyave sur Ehcache parce que c'est un peu plus léger et la configuration me semblait plus simple.
Importer Les Dépendances Maven
Ajoutez ces dépendances à votre fichier Maven pom et exécutez clean and packages. Ces fichiers sont les méthodes Guava dep et Spring helper à utiliser dans CacheBuilder.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
Configurer le Cache
Vous devez créer un fichier CacheConfig pour configurez le cache à L'aide de Java config.
@Configuration
@EnableCaching
public class CacheConfig {
public final static String CACHE_ONE = "cacheOne";
public final static String CACHE_TWO = "cacheTwo";
@Bean
public Cache cacheOne() {
return new GuavaCache(CACHE_ONE, CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build());
}
@Bean
public Cache cacheTwo() {
return new GuavaCache(CACHE_TWO, CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.build());
}
}
Annoter la méthode à mettre en cache
Ajoutez l'annotation @ Cacheable et transmettez le nom du cache.
@Service
public class CachedService extends WebServiceGatewaySupport implements CachedService {
@Inject
private RestTemplate restTemplate;
@Cacheable(CacheConfig.CACHE_ONE)
public String getCached() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> reqEntity = new HttpEntity<>("url", headers);
ResponseEntity<String> response;
String url = "url";
response = restTemplate.exchange(
url,
HttpMethod.GET, reqEntity, String.class);
return response.getBody();
}
}
Vous pouvez voir un exemple plus complet ici avec des captures d'écran annotées: Cache Goyave au printemps
J'utilise le piratage de la vie comme ceci
@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()));
}
Springboot 1.3.8
import java.util.concurrent.TimeUnit;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.cache.CacheBuilder;
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Override
@Bean
public CacheManager cacheManager() {
GuavaCacheManager cacheManager = new GuavaCacheManager();
return cacheManager;
}
@Bean
public CacheManager timeoutCacheManager() {
GuavaCacheManager cacheManager = new GuavaCacheManager();
CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(5, TimeUnit.SECONDS);
cacheManager.setCacheBuilder(cacheBuilder);
return cacheManager;
}
}
Et
@Cacheable(value="A", cacheManager="timeoutCacheManager")
public Object getA(){
...
}
Cela peut être fait en étendant org.springframework.cache.intercepteur.CacheInterceptor, et remplacer la méthode "doPut" - org.springframework.cache.intercepteur.AbstractCacheInvoker votre logique de remplacement doit utiliser la méthode put du fournisseur de cache qui sait définir TTL pour l'entrée du cache (dans mon cas, J'utilise HazelcastCacheManager)
@Autowired
@Qualifier(value = "cacheManager")
private CacheManager hazelcastCacheManager;
@Override
protected void doPut(Cache cache, Object key, Object result) {
//super.doPut(cache, key, result);
HazelcastCacheManager hazelcastCacheManager = (HazelcastCacheManager) this.hazelcastCacheManager;
HazelcastInstance hazelcastInstance = hazelcastCacheManager.getHazelcastInstance();
IMap<Object, Object> map = hazelcastInstance.getMap("CacheName");
//set time to leave 18000 secondes
map.put(key, result, 18000, TimeUnit.SECONDS);
}
Sur votre configuration de cache, vous devez ajouter ces 2 méthodes bean, en créant votre instance interceptor personnalisée .
@Bean
public CacheOperationSource cacheOperationSource() {
return new AnnotationCacheOperationSource();
}
@Primary
@Bean
public CacheInterceptor cacheInterceptor() {
CacheInterceptor interceptor = new MyCustomCacheInterceptor();
interceptor.setCacheOperationSources(cacheOperationSource());
return interceptor;
}
Cette solution est bonne quand vous voulez définir le TTL au niveau d'entrée, et non globalement au niveau du cache
Depuis Spring-boot 1.3.3, vous pouvez définir l'heure d'expiration dans CacheManager en utilisant RedisCacheManager.setExpires ou RedisCacheManager.setDefaultExpiration dansCacheManagerCustomizer rappel bean.