java - implementations - spring cache redis
¿Puedo configurar un TTL para @Cacheable (8)
Estoy probando el @Cacheable
anotación @Cacheable
para Spring 3.1 y me pregunto si hay alguna forma de borrar los datos en caché después de un tiempo configurando un TTL. Ahora mismo de lo que puedo ver, necesito aclararlo usando el @CacheEvict
, y al usar eso junto con @Scheduled
puedo hacer una implementación de TTL, pero parece demasiado para una tarea tan simple.
Aquí hay un ejemplo completo de cómo configurar Guava Cache en Spring. Usé Guava sobre Ehcache porque es un poco más liviano y la configuración me pareció más directa.
Importación Dependencias Maven
Agregue estas dependencias a su archivo maven pom y ejecute clean y packages. Estos archivos son los métodos Guava dep y Spring helper para usar en 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>
Configurar el caché
Necesita crear un archivo CacheConfig para configurar la memoria caché utilizando la configuración de 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());
}
}
Anotar el método que se almacenará en caché
Agregue la anotación @Cacheable y pase el nombre de la memoria caché.
@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();
}
}
Puede ver un ejemplo más completo aquí con capturas de pantalla anotadas: caché de guayaba en primavera
Desde Spring-boot 1.3.3, puede establecer el tiempo de caducidad en CacheManager utilizando RedisCacheManager.setExpires o RedisCacheManager.setDefaultExpiration en CacheManagerCustomizer call-back bean.
Primavera 3.1 y 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();
}
}
Si está trabajando con redis y Java 8, puede echarle un vistazo a JetCache :
@Cached(expire = 10, timeUnit = TimeUnit.MINUTES) User getUserById(long userId);
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;
}
}
y
@Cacheable(value="A", cacheManager="timeoutCacheManager")
public Object getA(){
...
}
Uso pirateo de la vida como este
@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()));
}
¿Cómo puedo configurar la función TTL / TTI / política de desalojo / XXX?
Directamente a través de su proveedor de caché. La abstracción de caché es ... bueno, una implementación de abstracción y no de caché
Entonces, si usa EHCache, use la configuración de EHCache para configurar el TTL.
También puede usar CacheBuilder de Guava para crear un caché y pasar la vista ConcurrentMap de este caché al método setStore del ConcurrentMapCacheFactoryBean .
esto se puede hacer extendiendo org.springframework.cache.interceptor.CacheInterceptor, y anulando el método "doPut" - org.springframework.cache.interceptor.AbstractCacheInvoker su lógica de anulación debe usar el método de almacenamiento del proveedor de caché que sabe establecer TTL para la entrada de caché (en mi caso uso 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);
}
en su configuración de caché necesita agregar esos 2 métodos de bean, creando su instancia de interceptor personalizada.
@Bean
public CacheOperationSource cacheOperationSource() {
return new AnnotationCacheOperationSource();
}
@Primary
@Bean
public CacheInterceptor cacheInterceptor() {
CacheInterceptor interceptor = new MyCustomCacheInterceptor();
interceptor.setCacheOperationSources(cacheOperationSource());
return interceptor;
}
Esta solución es buena cuando quiere establecer el TTL en el nivel de entrada, y no globalmente en el nivel de caché