ฉันสามารถตั้งค่า TTL สำหรับ @Cacheable ได้หรือไม่


109

ฉันกำลังลองใช้@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 / XXX ได้อย่างไร

โดยตรงผ่านผู้ให้บริการแคชของคุณ สิ่งที่เป็นนามธรรมของแคชคือ ... เอาล่ะสิ่งที่เป็นนามธรรมไม่ใช่การใช้แคช

ดังนั้นหากคุณใช้ EHCache ให้ใช้การกำหนดค่าของ EHCache เพื่อกำหนดค่า TTL

นอกจากนี้คุณยังสามารถใช้ฝรั่งของ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 ใน Spring ฉันใช้ Guava มากกว่า Ehcache เพราะน้ำหนักเบากว่าเล็กน้อยและ config ดูเหมือนตรงกับฉันมากกว่า

นำเข้าการพึ่งพา Maven

เพิ่มการอ้างอิงเหล่านี้ในไฟล์ maven pom ของคุณและรัน clean and package ไฟล์เหล่านี้เป็นวิธี 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();
    }
}

คุณสามารถดูตัวอย่างที่สมบูรณ์ยิ่งขึ้นได้ที่นี่พร้อมด้วยภาพหน้าจอที่มีคำอธิบายประกอบ: Guava Cache ใน Spring


2
หมายเหตุ: Guava cache เลิกใช้งานแล้วใน Spring 5 ( stackoverflow.com/questions/44175085/… )
Amin

37

ฉันใช้ชีวิตแฮ็คแบบนี้

@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 เกิดขึ้นได้อย่างไร ??
ใจรัตน์

รับมัน เราไม่ได้เรียกใช้วิธีนี้จากทุกที่ เรียกว่าหลังจากช่วงเวลา fixedDelay ขอบคุณสำหรับคำใบ้
ใจรัตน์

1
การล้างแคชทั้งหมดตามกำหนดเวลาอาจเป็นการแฮ็กที่สะดวกในการทำให้สิ่งต่างๆทำงานได้ แต่วิธีนี้ไม่สามารถใช้เพื่อให้รายการเป็น TTL ได้ แม้แต่ค่าเงื่อนไขก็สามารถประกาศได้ว่าจะลบแคชทั้งหมดหรือไม่ การอ้างอิงนี้เป็นความจริงที่ว่า ConcurrentMapCache เก็บออบเจ็กต์โดยไม่มีการประทับเวลาใด ๆ ดังนั้นจึงไม่มีวิธีประเมิน TTL ตามที่เป็นอยู่
jmb

เป็นรหัสที่นั่งของกางเกง (วิธีนี้ถูกขีดเขียนลง :))
Atum

แนวทางที่ดีและสะอาด
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

7

สามารถทำได้โดยการขยาย 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);



}

ในการกำหนดค่าแคชของคุณคุณต้องเพิ่มวิธีการ 2 bean เหล่านั้นสร้างอินสแตนซ์ interceptor ที่กำหนดเองของคุณ

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


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

วิธีนี้ใช้ได้ดีเมื่อคุณต้องการตั้งค่า TTL ในระดับเริ่มต้นไม่ใช่ระดับแคชทั่วโลก



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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.