Dapatkah saya menyetel TTL untuk @Cacheable

102

Saya mencoba @Cacheabledukungan anotasi untuk Spring 3.1 dan bertanya-tanya apakah ada cara untuk membuat data cache dihapus setelah beberapa saat dengan menyetel TTL? Sekarang dari apa yang dapat saya lihat, saya perlu membersihkannya sendiri dengan menggunakan @CacheEvict, dan dengan menggunakannya bersama-sama, @Scheduledsaya dapat membuat implementasi TTL sendiri tetapi tampaknya agak berlebihan untuk tugas yang begitu sederhana?

Piotr
sumber

Jawaban:

39

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

Bagaimana cara menyetel fitur TTL / TTI / Eviction policy / XXX?

Langsung melalui penyedia cache Anda. Abstraksi cache adalah ... ya, abstraksi bukan implementasi cache

Jadi, jika Anda menggunakan EHCache, gunakan konfigurasi EHCache untuk mengkonfigurasi TTL.

Anda juga dapat menggunakan CacheBuilder Guava untuk membuat cache, dan meneruskan tampilan ConcurrentMap cache ini ke metode setStore dari ConcurrentMapCacheFactoryBean .

JB Nizet
sumber
57

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

}
Magnus Heino
sumber
21
Untuk Spring 4.1 perluas CachingConfigurerSupport dan hanya menimpa cacheManager ().
Johannes Flügel
39

Berikut adalah contoh lengkap menyiapkan Guava Cache di Spring. Saya menggunakan Guava daripada Ehcache karena bobotnya sedikit lebih ringan dan konfigurasinya tampak lebih mudah bagi saya.

Impor Dependensi Maven

Tambahkan dependensi ini ke file pom maven Anda dan jalankan clean and packages. File ini adalah metode pembantu Guava dep dan Spring untuk digunakan di 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>

Konfigurasikan Cache

Anda perlu membuat file CacheConfig untuk mengkonfigurasi cache menggunakan konfigurasi 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());
   }
}

Beri anotasi metode yang akan disimpan dalam cache

Tambahkan anotasi @Cacheable dan teruskan nama cache.

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

Anda dapat melihat contoh yang lebih lengkap di sini dengan screenshot beranotasi: Guava Cache in Spring

anataliocs
sumber
2
Catatan: Cache jambu biji sekarang tidak digunakan lagi di Musim Semi 5 ( stackoverflow.com/questions/44175085/… )
Amin
33

Saya menggunakan peretasan hidup seperti ini

@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()));
}
Atum
sumber
Apakah Anda memanggil reportCacheEvictmetode dari mana saja. Bagaimana cacheEvict terjadi ??
Jaikrat
Mengerti. Kami tidak memanggil metode ini dari mana pun. Ini disebut setelah interval waktu fixedDelay. Terima kasih atas petunjuknya.
Jaikrat
1
Menghapus seluruh cache pada jadwal bisa menjadi peretasan yang berguna untuk membuat semuanya berfungsi, tetapi metode ini tidak dapat digunakan untuk memberi item TTL. Bahkan nilai kondisi hanya dapat menyatakan apakah akan menghapus seluruh cache. Yang mendasari ini adalah fakta bahwa ConcurrentMapCache menyimpan objek tanpa stempel waktu apa pun, jadi tidak ada cara untuk mengevaluasi TTL sebagaimana adanya.
jmb
adalah kode kursi-of-the-pants (metode ini telah ditulis :)).
Atum
Pendekatan yang bagus dan bersih
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;
}

}

dan

@Cacheable(value="A", cacheManager="timeoutCacheManager")
public Object getA(){
...
}
jo8937
sumber
Luar biasa! Ini persis seperti yang saya cari
MerLito
6

ini bisa dilakukan dengan memperluas org.springframework.cache.interceptor.CacheInterceptor, dan menimpa metode "doPut" - org.springframework.cache.interceptor.AbstractCacheInvoker logika penggantian Anda harus menggunakan metode penyedia cache put yang tahu untuk menyetel TTL untuk entri cache (dalam kasus saya, saya menggunakan 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);



}

pada konfigurasi cache Anda, Anda perlu menambahkan 2 metode kacang tersebut, membuat instance interseptor kustom Anda.

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


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

Solusi ini bagus saat Anda ingin menyetel TTL pada level entri, dan bukan secara global pada level cache

lukass77
sumber
2

Sejak Spring-boot 1.3.3, Anda dapat menyetel waktu kedaluwarsa di CacheManager dengan menggunakan RedisCacheManager.setExpires atau RedisCacheManager.setDefaultExpiration dalam kacang panggilan balik CacheManagerCustomizer .

Andrew
sumber
0

Saat menggunakan Redis, TTL dapat diatur di file properti seperti ini:

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

Hamid Mohayeji
sumber
-2

Jika Anda bekerja dengan redis dan Java 8, Anda dapat melihat JetCache :

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

Huang Li
sumber
1
Pertanyaan untuk musim semi adalah anotasi
@Cacheable