本文共 4333 字,大约阅读时间需要 14 分钟。
- 可以根据需要,让某些key,默认TTL与基础设置不同,直接看代码 这不是重点,只是可以提前DIY一些东西
@Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 配置序列化 // 统一默认配置,TTL为60秒 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(60)); // 针对不同key可以个性化设置 SetcacheNames = new HashSet<>(); cacheNames.add("account"); cacheNames.add("post"); // 对每个缓存空间应用不同的配置 Map 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(); }
上面的设置虽然可以提前设定每个cacheName的ttl,但是不够细,虽然Cacheable的sync可以防止缓存击穿,但是无法防止缓存雪崩。
我们可以使用AOP来完成自动刷新和自定义TTL。 代码写的比较糙,只是个例子,可以自己修改。
import org.springframework.core.annotation.AliasFor;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Inheritedpublic @interface CacheTTL { @AliasFor("ttl") long value() default 60; @AliasFor("value") long ttl() default 60; long preExpireRefresh() default 10;}
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@Componentpublic class CustomCacheAspect { private final RedisTemplateredisTemplate; private final SimpleKeyGenerator keyGenerator = new SimpleKeyGenerator(); private final AtomicInteger asyncLock = new AtomicInteger(0); public CustomCacheAspect(RedisTemplate 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); }
转载地址:http://yxlsi.baihongyu.com/