Czy mogę ustawić TTL dla @Cacheable


106

Staram się o @Cacheablewsparcie dla adnotacji wiosny 3.1 i zastanawiasz się, czy jest jakiś sposób, aby dane w pamięci podręcznej usunąć po pewnym czasie przez ustawienie TTL? W tej chwili z tego, co widzę, muszę sam to wyczyścić za pomocą @CacheEvict, a używając tego razem z @Scheduledmogę samodzielnie wykonać implementację TTL, ale wydaje się, że to trochę za dużo jak na tak proste zadanie?

Odpowiedzi:


39

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

Jak mogę ustawić funkcję TTL / TTI / Eviction / XXX?

Bezpośrednio przez dostawcę pamięci podręcznej. Abstrakcja pamięci podręcznej jest ... cóż, abstrakcją, a nie implementacją pamięci podręcznej

Tak więc, jeśli używasz EHCache, użyj konfiguracji EHCache, aby skonfigurować TTL.

Możesz również użyć CacheBuilder Guavy do zbudowania pamięci podręcznej i przekazać widok ConcurrentMap tej pamięci podręcznej do metody setStore ConcurrentMapCacheFactoryBean .


58

Wiosna 3.1 i Guawa 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
W przypadku Spring 4.1 rozszerz CachingConfigurerSupport i nadpisuj tylko cacheManager ().
Johannes Flügel

40

Oto pełny przykład konfiguracji Guava Cache na wiosnę. Użyłem guawy zamiast Ehcache, ponieważ jest nieco lżejszy, a konfiguracja wydawała mi się prostsza.

Importuj zależności Maven

Dodaj te zależności do pliku pom maven i uruchom czyste i pakiety. Te pliki są metodami pomocniczymi Guava dep i Spring do użycia w 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>

Skonfiguruj pamięć podręczną

Musisz utworzyć plik CacheConfig, aby skonfigurować pamięć podręczną przy użyciu konfiguracji Java.

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

Opisz metodę, która ma być buforowana

Dodaj adnotację @Cacheable i podaj nazwę pamięci podręcznej.

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

Możesz zobaczyć bardziej kompletny przykład tutaj z opisami zrzutów ekranu: Guava Cache in Spring


2
Uwaga: pamięć podręczna guawy jest teraz przestarzała na wiosnę 5 ( stackoverflow.com/questions/44175085/… )
Amin

35

Używam hakowania życia w ten sposób

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

Czy wywołujesz reportCacheEvictmetodę z dowolnego miejsca. Jak dzieje się cacheEvict?
Jaikrat

Zdobyć. Nie wywołujemy tej metody z dowolnego miejsca. Jest wywoływana po interwale czasu fixedDelay. Dzięki za podpowiedź.
Jaikrat

1
Wyczyszczenie całej pamięci podręcznej zgodnie z harmonogramem może być poręcznym hakiem, aby wszystko działało, ale ta metoda nie może być używana do nadawania elementom TTL. Nawet wartość warunku może tylko zadeklarować, czy usunąć całą pamięć podręczną. U podstaw tego leży fakt, że ConcurrentMapCache przechowuje obiekty bez żadnego znacznika czasu, więc nie ma sposobu, aby ocenić TTL tak, jak jest.
jmb

to kod siedziska spodni (ta metoda została zapisana :)).
Atum

Ładne i czyste podejście
lauksas

31

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

}

i

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

Niesamowity! Właśnie tego szukałem
MerLito

7

można to zrobić rozszerzając org.springframework.cache.interceptor.CacheInterceptor i zastępując metodę „doPut” - org.springframework.cache.interceptor.AbstractCacheInvoker Twoja logika override powinna używać metody put dostawcy pamięci podręcznej, która wie, jak ustawić TTL dla wpisu pamięci podręcznej (w moim przypadku używam 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);



}

w konfiguracji pamięci podręcznej musisz dodać te dwie metody fasoli, tworząc niestandardową instancję przechwytującą.

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


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

To rozwiązanie jest dobre, gdy chcesz ustawić TTL na poziomie podstawowym, a nie globalnie na poziomie pamięci podręcznej



1

Podczas korzystania z Redis TTL można ustawić w pliku właściwości w następujący sposób:

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

Jeśli pracujesz z redis i Java 8, możesz rzucić okiem na JetCache :

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


1
pytanie jest na wiosnę @Cacheable adnotation
satyesht
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.