Могу ли я установить TTL для @Cacheable - PullRequest
81 голосов
/ 18 ноября 2011

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

Ответы [ 8 ]

48 голосов
/ 29 августа 2012

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

}
35 голосов
/ 18 ноября 2011

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

Как настроить функцию TTL / TTI / Политика по выселению / XXX?

Непосредственно через поставщика кеша. Абстракция кеша ... ну, абстракция не реализация кеша

Итак, если вы используете EHCache, используйте конфигурацию EHCache для настройки TTL.

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

31 голосов
/ 10 августа 2015

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

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

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

25 голосов
/ 08 июля 2016

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

@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()));
}
22 голосов
/ 24 ноября 2016

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(){
...
}
5 голосов
/ 01 февраля 2017

это можно сделать, расширив 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 голосов
/ 12 июля 2016

Начиная с Spring-boot 1.3.3, вы можете установить время истечения в CacheManager, используя RedisCacheManager.setExpires или RedisCacheManager.setDefaultExpiration в CacheManagerCustomizer обратный вызовбоб.

0 голосов
/ 15 мая 2018

Если вы работаете с Redis и Java 8, вы можете взглянуть на JetCache :

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...