Java 我可以为@Cacheable设置TTL吗

Java 我可以为@Cacheable设置TTL吗,java,spring,Java,Spring,我正在试用Spring3.1的@Cacheable注释支持,想知道是否有任何方法可以通过设置TTL在一段时间后清除缓存的数据? 现在,从我所能看到的,我需要通过使用@cacheexecute来清除它,并且通过与@Scheduled一起使用,我可以自己实现一个TTL,但对于这样一个简单的任务来说,似乎有点太多了?请参见: 如何设置TTL/TTI/逐出策略/XXX功能 直接通过缓存提供程序。缓存抽象是。。。 嗯,抽象不是缓存实现 因此,如果您使用EHCache,请使用EHCache的配置来配置TTL

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

请参见:

如何设置TTL/TTI/逐出策略/XXX功能

直接通过缓存提供程序。缓存抽象是。。。 嗯,抽象不是缓存实现

因此,如果您使用EHCache,请使用EHCache的配置来配置TTL


您还可以使用Guava构建缓存,并将此缓存的ConcurrentMap视图传递给。

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

}

下面是在春季设置番石榴缓存的完整示例。我使用番石榴而不是Ehcache,因为它的重量稍轻,而且配置对我来说更直接

导入Maven依赖项

将这些依赖项添加到maven pom文件中,然后运行clean和packages。这些文件是在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>
注释要缓存的方法

添加@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();
    }
}
@服务
公共类CachedService扩展WebService网关支持实现CachedService{
@注入
私有RestTemplate RestTemplate;
@可缓存(CacheConfig.CACHE\u ONE)
公共字符串getCached(){
HttpHeaders=新的HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity reqEntity=新的HttpEntity(“url”,标题);
反应性反应;
字符串url=“url”;
response=restTemplate.exchange(
网址,
HttpMethod.GET、reqEntity、String.class);
返回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()));
}

从Spring boot 1.3.3开始,您可以使用回调bean中的RedisCacheManager.setExpires或RedisCacheManager.setDefaultExpire在CacheManager中设置过期时间

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

}

这可以通过扩展org.springframework.cache.interceptor.CacheInterceptor来实现,并重写“doPut”方法-org.springframework.cache.interceptor.AbstractCacheInvoker 重写逻辑应该使用缓存提供程序put方法,该方法知道为缓存条目设置TTL(在我的例子中,我使用HazelcastCacheManager)


当您希望在入口级别设置TTL,而不是在缓存级别全局设置TTL时,此解决方案很好。如果您正在使用redis和Java 8,您可以查看:

@Cached(expire=10,timeUnit=timeUnit.MINUTES)
用户getUserById(长用户ID);

使用Redis时,可以在属性文件中设置TTL,如下所示:

spring.cache.redis.time to live=1d#1天

spring.cache.redis.time to live=5m#5分钟


spring.cache.redis.time to live=10s#10秒

对我来说,最简单的方法是使用咖啡因缓存,它可以直接在
应用程序.yml
文件中配置

您可以通过
expireAfterWrite
参数设置TTL。示例配置如下所示:

spring:
  cache:
    caffeine:
      spec: expireAfterWrite=15m
    cache-names: mycache

这将在15分钟后逐出元素。

对于Spring 4.1,扩展CachingConfigurerSupport并仅覆盖cacheManager()。是否从任何位置调用
ReportCacheExit
方法。缓存驱逐是怎么发生的?明白了。我们不会从任何地方调用此方法。它在固定的延迟时间间隔后调用。谢谢你的提示。按计划清除整个缓存可以是一种方便的方法,可以让事情正常进行,但这种方法不能用于为项目提供TTL。即使条件值也只能声明是否删除整个缓存。这是因为ConcurrentMapCache存储的对象没有任何时间戳,因此无法评估TTL as-is.is代码(此方法被潦草地写下:)。非常好而且干净的方法令人惊讶!这正是我想要的注意:Guava缓存现在在Spring5中被弃用了()问题是针对Spring@Cacheable的annotation@satyesht不知道为什么要投-5票。
@Cacheable(value="A", cacheManager="timeoutCacheManager")
public Object getA(){
...
}
@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
public CacheOperationSource cacheOperationSource() {
    return new AnnotationCacheOperationSource();
}


@Primary
@Bean
public CacheInterceptor cacheInterceptor() {
    CacheInterceptor interceptor = new MyCustomCacheInterceptor();
    interceptor.setCacheOperationSources(cacheOperationSource());    
    return interceptor;
}
spring:
  cache:
    caffeine:
      spec: expireAfterWrite=15m
    cache-names: mycache