我可以为@Cacheable设置TTL吗


101

我正在尝试@Cacheable对Spring 3.1 的注释支持,并且想知道是否有任何方法可以通过设置TTL在一段时间后清除缓存的数据?现在,从我看到的内容中,我需要使用@CacheEvict和自己清除它,并与@Scheduled我一起使用可以实现TTL实现,但是对于这样一个简单的任务来说似乎有点多了吗?

Answers:


39

参见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视图传递给ConcurrentMapCacheFactoryBean的setStore方法


57

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()。
JohannesFlügel'16

39

这是在Spring中设置Guava Cache的完整示例。我在Ehcache上使用了Guava,因为它的重量更轻,而且配置对我来说似乎更直接。

导入Maven依赖项

将这些依赖项添加到您的maven pom文件中,然后运行clean和package。这些文件是在CacheBuilder中使用的Guava dep和Spring帮助器方法。

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

您可以在此处看到带有注释屏幕截图的更完整示例: Spring中的Guava Cache


2
注:番石榴缓存现已弃用春5(stackoverflow.com/questions/44175085/...
阿明Ziaei

33

我像这样使用生活黑客

@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 2013年

得到它。我们不会在任何地方调用此方法。在fixedDelay时间间隔之后调用它。感谢您的提示。
Jaikrat

1
按计划清除整个缓存可能是使事情正常进行的便捷工具,但是该方法不能用于为项目提供TTL。即使条件值也只能声明是否删除整个缓存。这是因为ConcurrentMapCache存储对象时没有任何时间戳,因此无法按原样评估TTL。
JMB

是代码“裤子”(此方法被写成:))。
Atum

干净整洁的方法
lauksas

30

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

6

这可以通过扩展org.springframework.cache.interceptor.CacheInterceptor并覆盖“ doPut”方法来完成-org.springframework.cache.interceptor.AbstractCacheInvoker您的覆盖逻辑应使用知道为缓存条目设置TTL的缓存提供程序put方法。 (在我的情况下,我使用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);



}

在缓存配置上,您需要添加这两个bean方法,以创建自定义拦截器实例。

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


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

当您要在条目级别而不是在缓存级别全局设置TTL时,此解决方案非常有用


2

由于春季启动1.3.3,您可以设置使用期满在CacheManager中时间RedisCacheManager.setExpiresRedisCacheManager.setDefaultExpirationCacheManagerCustomizer回拨豆。


0

使用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注释
satyesht
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.