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?

64
demandé sur Soumitri Pattnaik 2011-11-18 15:34:45

8 réponses

Voir http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#cache-specific-config:

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.

29
répondu JB Nizet 2011-11-18 11:54:09

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();
    }

}
39
répondu Magnus Heino 2012-08-29 09:34:19

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

27
répondu anataliocs 2015-09-05 15:03:41

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()));
}
21
répondu Atum 2016-07-08 08:03:36

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(){
...
}
18
répondu jo8937 2016-11-24 14:27:31

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

2
répondu lukass77 2017-02-01 12:05:49

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.

1
répondu Andrew 2017-12-18 16:01:10

Si vous travaillez avec redis et Java 8, Vous pouvez jeter un oeil à JetCache :

@Cached(expire = 10, timeUnit = TimeUnit.MINUTES) User getUserById(long userId);

0
répondu Huang Li 2018-05-15 07:44:43