Могу ли я установить TTL для @Cacheable


108

Я пробую @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.

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


58

Spring 3.1 и 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
Для Spring 4.1 расширьте CachingConfigurerSupport и перезапишите только cacheManager ().
Johannes Flügel

40

Вот полный пример настройки Guava Cache весной. Я использовал Guava вместо Ehcache, потому что он немного легче и конфигурация мне показалась более простой.

Импортировать зависимости Maven

Добавьте эти зависимости в свой файл maven pom и запустите clean и packages. Эти файлы являются вспомогательными методами 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();
    }
}

Здесь вы можете увидеть более полный пример с аннотированными скриншотами: Guava Cache in Spring


2
Примечание. Кеш Guava теперь устарел в Spring 5 ( stackoverflow.com/questions/44175085/… )
Амин

36

Я использую лайфхаки вот так

@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метод из любого места. Как происходит cacheEvict ??
Jaikrat

Возьми. Мы не вызываем этот метод ниоткуда. Вызывается после временного интервала fixedDelay. Спасибо за подсказку.
Jaikrat

1
Очистка всего кеша по расписанию может быть удобным приемом для работы, но этот метод нельзя использовать для задания TTL элементам. Даже значение условия может только указать, нужно ли удалить весь кеш. В основе этого лежит тот факт, что ConcurrentMapCache хранит объекты без какой-либо временной метки, поэтому нет возможности оценить TTL как есть.
jmb

- это кодовое «сиденье в штанах» (этот метод был нацарапан :)).
Атум

Хороший и чистый подход
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;
}

}

а также

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

Удивительный! Это было именно то, что я искал
MerLito

7

это можно сделать, расширив org.springframework.cache.interceptor.CacheInterceptor и переопределив метод «doPut» - org.springframework.cache.interceptor.AbstractCacheInvoker, ваша логика переопределения должна использовать метод put провайдера кеша, который знает, как установить 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);



}

в вашей конфигурации кеша вам нужно добавить эти 2 метода 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 .


1

При использовании 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
вопрос для весны @Cacheable annotation
satyesht
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.