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


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

8 64

8 ответов:

см 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 для настройки ТТЛ.

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

Весна 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();
    }

}

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

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

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

аннотировать метод для кэширования

добавьте аннотацию @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();
    }
}

вы можете увидеть более полный пример здесь с аннотированные скриншоты: гуава кэш весной

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

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

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(){
...
}

Это можно сделать путем расширения организации.springframework.кэш.перехватчик.CacheInterceptor, и переопределить метод "doPut" - org.springframework.кэш.перехватчик.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 на начальном уровне, а не глобально на уровне кэша

начиная с Spring-boot 1.3.3, вы можете установить время истечения срока действия в CacheManager с помощью RedisCacheManager.setExpires или RedisCacheManager.setDefaultExpiration на CacheManagerCustomizer call-back bean.

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

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