Posso impostare un TTL per @Cacheable


101

Sto provando il @Cacheablesupporto delle annotazioni per Spring 3.1 e mi chiedo se esiste un modo per cancellare i dati memorizzati nella cache dopo un po 'di tempo impostando un TTL? In questo momento da quello che posso vedere ho bisogno di cancellarlo da solo usando il @CacheEvict, e usandolo insieme @Scheduledposso fare un'implementazione TTL da solo, ma sembra un po 'troppo per un compito così semplice?

Risposte:


39

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

Come posso impostare la funzione TTL / TTI / Sfratto / XXX?

Direttamente tramite il tuo provider di cache. L'astrazione della cache è ... beh, un'astrazione non un'implementazione della cache

Quindi, se usi EHCache, usa la configurazione di EHCache per configurare il TTL.

È inoltre possibile utilizzare CacheBuilder di Guava per creare una cache e passare la vista ConcurrentMap di questa cache al metodo setStore di ConcurrentMapCacheFactoryBean .


57

Spring 3.1 e Guava 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();
    }

}

21
Per Spring 4.1 estendere CachingConfigurerSupport e sovrascrivere solo cacheManager ().
Johannes Flügel

39

Ecco un esempio completo di come configurare Guava Cache in primavera. Ho usato Guava su Ehcache perché è un po 'più leggero e la configurazione mi è sembrata più semplice.

Importa dipendenze Maven

Aggiungi queste dipendenze al tuo file pom di Maven ed esegui clean and packages. Questi file sono i metodi Guava dep e Spring helper da utilizzare nel 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>

Configura la cache

È necessario creare un file CacheConfig per configurare la cache utilizzando 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());
   }
}

Annota il metodo da memorizzare nella cache

Aggiungi l'annotazione @Cacheable e passa il nome della 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();
    }
}

Puoi vedere un esempio più completo qui con screenshot annotati: Guava Cache in Spring


2
Nota: la cache Guava è ora deprecata nella primavera 5 ( stackoverflow.com/questions/44175085/… )
Amin Ziaei

33

Uso l'hacking della vita in questo modo

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

Stai chiamando il reportCacheEvictmetodo da qualsiasi luogo. Come sta succedendo cacheEvict ??
Jaikrat

Prendilo. Non stiamo chiamando questo metodo da nessuna parte. Viene chiamato dopo l'intervallo di tempo fixedDelay. Grazie per il suggerimento.
Jaikrat

1
Svuotare l'intera cache in base a una pianificazione può essere un trucco utile per far funzionare le cose, ma questo metodo non può essere utilizzato per assegnare agli elementi un TTL. Anche il valore della condizione può solo dichiarare se eliminare l'intera cache. Alla base di questo c'è il fatto che ConcurrentMapCache memorizza gli oggetti senza alcun timestamp, quindi non c'è modo di valutare un TTL così com'è.
jmb

è il codice seat-of-the-pants (questo metodo è stato scarabocchiato :)).
Atum

Approccio piacevole e pulito
lauksas

30

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

}

e

@Cacheable(value="A", cacheManager="timeoutCacheManager")
public Object getA(){
...
}

Sorprendente! Questo era esattamente quello che stavo cercando
MerLito

6

questo può essere fatto estendendo org.springframework.cache.interceptor.CacheInterceptor e sovrascrivendo il metodo "doPut" - org.springframework.cache.interceptor.AbstractCacheInvoker la tua logica di override dovrebbe utilizzare il metodo put del provider di cache che sa impostare TTL per la cache entry (nel mio caso utilizzo 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);



}

nella configurazione della cache è necessario aggiungere questi 2 metodi bean, creando la propria istanza di intercettazione personalizzata.

@Bean
public CacheOperationSource cacheOperationSource() {
    return new AnnotationCacheOperationSource();
}


@Primary
@Bean
public CacheInterceptor cacheInterceptor() {
    CacheInterceptor interceptor = new MyCustomCacheInterceptor();
    interceptor.setCacheOperationSources(cacheOperationSource());    
    return interceptor;
}

Questa soluzione è utile quando si desidera impostare il TTL a livello di ingresso e non a livello globale a livello di cache


2

A partire da Spring-boot 1.3.3, è possibile impostare l'ora di scadenza in CacheManager utilizzando RedisCacheManager.setExpires o RedisCacheManager.setDefaultExpiration nel bean di richiamata CacheManagerCustomizer .


0

Quando si utilizza Redis, TTL può essere impostato nel file delle proprietà in questo modo:

spring.cache.redis.time-to-live=1d # 1 day

spring.cache.redis.time-to-live=5m # 5 minutes

spring.cache.redis.time-to-live=10s # 10 seconds


-2

Se stai lavorando con redis e Java 8, puoi dare un'occhiata a JetCache :

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


1
la domanda è per l'annotazione Spring @Cacheable
satyesht
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.