TTL刷新时间是什么

发布网友 发布时间:2022-04-21 19:00

我来回答

1个回答

热心网友 时间:2023-11-03 09:08

@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 配置序列化
// 统一默认配置,TTL为60秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(60));

// 针对不同key可以个性化设置
Set<String> cacheNames = new HashSet<>();
cacheNames.add("account");
cacheNames.add("post");

// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("account", config.entryTtl(Duration.ofSeconds(30)));
configMap.put("post", config);

return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(config)
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
}
自定义每个缓存的TTL和自动刷新
上面的设置虽然可以提前设定每个cacheName的ttl,但是不够细,虽然Cacheable的sync可以防止缓存击穿,但是无法防止缓存雪崩。
我们可以使用AOP来完成自动刷新和自定义TTL。
代码写的比较糙,只是个例子,可以自己修改。

自己写TTL注解
import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface CacheTTL {
@AliasFor("ttl")
long value() default 60;

@AliasFor("value")
long ttl() default 60;

long preExpireRefresh() default 10;
}
AOP实现
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

//这里必须要比Cacheable的Aspect优先级要高
@Order(value=1)
@Aspect
@Component
public class CustomCacheAspect {

private final RedisTemplate<String,Object> redisTemplate;
private final SimpleKeyGenerator keyGenerator = new SimpleKeyGenerator();
private final AtomicInteger asyncLock = new AtomicInteger(0);

public CustomCacheAspect(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

@After(value="execution(* *..*.*(..))")
public void after(JoinPoint point)
{
Object target = point.getTarget();

MethodSignature signature = (MethodSignature) point.getSignature();

Method method = signature.getMethod();

try {
if (method.isAnnotationPresent(CacheTTL.class) && method.isAnnotationPresent(Cacheable.class)) {
CacheTTL ttlData = AnnotationUtils.getAnnotation(method, CacheTTL.class);
Cacheable cacheAbleData = AnnotationUtils.getAnnotation(method, Cacheable.class);

long ttl = ttlData.ttl();
long preExpireRefresh = ttlData.preExpireRefresh();

String[] cacheNames = cacheAbleData.cacheNames();
//默认的keyGenerator生成,如果自定义了自己改一下
Object key = keyGenerator.generate(target, method, point.getArgs());

updateExpire(cacheNames,key,preExpireRefresh,ttl);
}
} catch (Exception e) {
e.printStackTrace();
}
}

public void updateExpire(String[] cacheNames,Object key,long preExpireRefresh,long ttl){
if (asyncLock.compareAndSet(0,1)){
Arrays.stream(cacheNames).parallel().forEach(cacheName->{
cacheName = cacheName + "::" + key;
long expire = redisTemplate.getExpire(cacheName,TimeUnit.SECONDS);
if (expire>0 && expire<=preExpireRefresh || expire > ttl || expire == -1){
redisTemplate.expire(cacheName, ttl, TimeUnit.SECONDS);
}
});
asyncLock.set(0);
}

}

}
使用
@Cacheable(cacheNames = "account",key="#id",sync = true)
@CacheTTL(ttl = 60,preExpireRefresh = 10)
public Account findAccountByID(int id) {
return accountDao.findAccountByID(id);
}

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com