Чи можу я встановити TTL для @Cacheable


102

Я випробовую @Cacheableпідтримку анотацій для Spring 3.1 і цікавлюся, чи є спосіб як-небудь очистити кешовані дані через деякий час, встановивши TTL? Зараз з того, що я бачу, мені потрібно це очистити самостійно, використовуючи @CacheEvict, і використовуючи це разом з @Scheduledя можу зробити реалізацію TTL самостійно, але це здається трохи для такого простого завдання?

Відповіді:


39

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

Як я можу встановити функцію TTL / TTI / Eviction policy / XXX?

Безпосередньо через постачальника кешу. Абстракція кешу - це ... ну, абстракція не є реалізацією кешу

Отже, якщо ви використовуєте EHCache, використовуйте конфігурацію EHCache для налаштування TTL.

Ви також можете використовувати CacheBuilder від Guava для побудови кешу та передати подання ConcurrentMap цього кешу до методу setStore методу ConcurrentMapCacheFactoryBean .


57

Весна 3.1 та Гуава 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
Для Spring 4.1 розширити CachingConfigurerSupport і лише перезаписати cacheManager ().
Йоганнес Флюгель

39

Ось повний приклад налаштування кешу гуави навесні. Я використовував Guava над Ehcache, оскільки він трохи легший, і конфігурація здалася мені більш прямою.

Імпортувати залежності Maven

Додайте ці залежності до свого файлу maven pom і запустіть clean та пакети. Ці файли - це допоміжні методи Guava dep та Spring, які використовуються в 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>

Налаштуйте кеш

Вам потрібно створити файл CacheConfig, щоб налаштувати кеш за допомогою конфігурації 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());
   }
}

Помітьте метод, який буде кешовано

Додайте анотацію @Cacheable та передайте ім'я кешу.

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

Тут ви можете побачити більш повний приклад із анотованими скріншотами: Кеш гуави навесні


2
Примітка: Кеш-пам’ять Guava тепер застаріла навесні 5 ( stackoverflow.com/questions/44175085/… )
Амін Зяей

33

Я використовую лайфхаки так

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

Ви викликаєте reportCacheEvictметод з будь-якого місця. Як відбувається кеш-виселення ??
Jaikrat

Отримайте. Ми нікуди не викликаємо цей метод. Його викликають після фіксованого інтервалу часу. Дякую за підказку.
Jaikrat

1
Очищення всього кешу за розкладом може бути зручним хаком, щоб все запрацювало, але цей метод не можна використовувати для надання елементам TTL. Навіть значення умови може лише визначити, чи видаляти весь кеш. В основі цього лежить той факт, що ConcurrentMapCache зберігає об'єкти без позначки часу, тому немає можливості оцінити TTL як є.
jmb

є кодовим сидінням штанів (цей метод був записаний :)).
Атум

Хороший і чистий підхід
lauksas

31

Спрінгбот 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;
}

}

і

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

Дивовижний! Це було саме те, що я шукав
MerLito

6

це можна зробити, розширивши org.springframework.cache.interceptor.CacheInterceptor і перевизначивши метод "doPut" - org.springframework.cache.interceptor.AbstractCacheInvoker Ваша логіка перевизначення повинна використовувати метод постачання кешу, який знає, щоб встановити TTL для введення кешу (у моєму випадку я використовую 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);



}

у вашій конфігурації кешу вам потрібно додати ці два методи bean, створюючи власний екземпляр перехоплювача.

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


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

Це рішення добре, коли ви хочете встановити TTL на початковому рівні, а не глобально на рівні кешу


2

Починаючи з Spring-boot 1.3.3, ви можете встановити термін дії у CacheManager, використовуючи RedisCacheManager.setExpires або RedisCacheManager.setDefaultExpiration в CacheManagerCustomizer .


0

При використанні Redis TTL можна встановити у файлі властивостей таким чином:

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

Якщо ви працюєте з redis та Java 8, ви можете поглянути на JetCache :

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


1
питання для анотації spring @Cacheable
satyesht
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.