Spring @Cacheable指定失效时间实例

2023-01-21 0 4,677

目录

Spring @Cacheable指定失效时间

新版本配置

@Configuration
@EnableCaching
public class RedisCacheConfig {
    @Bean
    public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
        return (builder) -> {
            for (Map.Entry<String, Duration> entry : RedisCacheName.getCacheMap().entrySet()) {
                builder.withCacheConfiguration(entry.getKey(),
                        RedisCacheConfiguration.defaultCacheConfig().entryTtl(entry.getValue()));
            }
        };
    }
 
    public static class RedisCacheName { 
        public static final String CACHE_10MIN = \"CACHE_10MIN\"; 
        @Getter
        private static final Map<String, Duration> cacheMap; 
        static {
            cacheMap = ImmutableMap.<String, Duration>builder().put(CACHE_10MIN, Duration.ofSeconds(10L)).build();
        } 
    } 
 
}

版本配置

interface CacheNames{
    String CACHE_15MINS = \"sssss:cache:15m\";
        /** 30分钟缓存组 */
    String CACHE_30MINS = \"sssss:cache:30m\";
        /** 60分钟缓存组 */
    String CACHE_60MINS = \"sssss:cache:60m\";
        /** 180分钟缓存组 */
    String CACHE_180MINS = \"sssss:cache:180m\";
}
 
@Component
 public class RedisCacheCustomizer
            implements CacheManagerCustomizer<RedisCacheManager> {
        /** CacheManager缓存自定义初始化比较早,尽量不要@autowired 其他spring 组件 */
        @Override
        public void customize(RedisCacheManager cacheManager) {
            // 自定义缓存名对应的过期时间
            Map<String, Long> expires = ImmutableMap.<String, Long>builder()
                    .put(CacheNames.CACHE_15MINS, TimeUnit.MINUTES.toSeconds(15))
                    .put(CacheNames.CACHE_30MINS, TimeUnit.MINUTES.toSeconds(30))
                    .put(CacheNames.CACHE_60MINS, TimeUnit.MINUTES.toSeconds(60))
                    .put(CacheNames.CACHE_180MINS, TimeUnit.MINUTES.toSeconds(180)).build();
            // spring cache是根据cache name查找缓存过期时长的,如果找不到,则使用默认值
            cacheManager.setDefaultExpiration(TimeUnit.MINUTES.toSeconds(30));
            cacheManager.setExpires(expires);
        }
    } 
 
  @Cacheable(key = \"key\", cacheNames = CacheNames.CACHE_15MINS)
    public String demo2(String key) {
        return \"abc\" + key;
  }

@Cacheable缓存失效时间策略默认实现及扩展

之前对Spring缓存的理解是每次设置缓存之后,重复请求会刷新缓存时间,但是问题排查阅读源码发现,跟自己的理解大相径庭。所有的你以为都仅仅是你以为!!!!

背景

目前项目使用的spring缓存,主要是CacheManager、Cache以及@Cacheable注解,Spring现有的缓存注解无法单独设置每一个注解的失效时间,Spring官方给的解释:Spring Cache是一个抽象而不是一个缓存实现方案。

因此对于缓存失效时间(TTL)的策略依赖于底层缓存中间件,官方给举例:ConcurrentMap是不支持失效时间的,而Redis是支持失效时间的。

Spring @Cacheable指定失效时间实例

Spring Cache Redis实现

Spring缓存注解@Cacheable底层的CacheManager与Cache如果使用Redis方案的话,首次设置缓存数据之后,每次重复请求相同方法读取缓存并不会刷新失效时间,这是Spring的默认行为(受一些缓存影响,一直以为每次读缓存也会刷新缓存失效时间)。

可以参见源码:

org.springframework.cache.interceptor.CacheAspectSupport#execute(org.springframework.cache.interceptor.CacheOperationInvoker, java.lang.reflect.Method, org.springframework.cache.interceptor.CacheAspectSupport.CacheOperationContexts)

private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
		// Special handling of synchronized invocation
		if (contexts.isSynchronized()) {
			CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
			if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
				Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
				Cache cache = context.getCaches().iterator().next();
				try {
					return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
				}
				catch (Cache.ValueRetrievalException ex) {
					// The invoker wraps any Throwable in a ThrowableWrapper instance so we
					// can just make sure that one bubbles up the stack.
					throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
				}
			}
			else {
				// No caching required, only call the underlying method
				return invokeOperation(invoker);
			}
		} 
 
		// Process any early evictions
		processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
				CacheOperationExpressionEvaluator.NO_RESULT);
 
		// Check if we have a cached item matching the conditions
		Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
 
		// Collect puts from any @Cacheable miss, if no cached item is found
		List<CachePutRequest> cachePutRequests = new LinkedList<>();
		if (cacheHit == null) {
			collectPutRequests(contexts.get(CacheableOperation.class),
					CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
		} 
		Object cacheValue;
		Object returnValue;
 
		if (cacheHit != null && !hasCachePut(contexts)) {
			// If there are no put requests, just use the cache hit
			cacheValue = cacheHit.get();
			returnValue = wrapCacheValue(method, cacheValue);
		}
		else {
			// Invoke the method if we don\'t have a cache hit
			returnValue = invokeOperation(invoker);
			cacheValue = unwrapReturnValue(returnValue);
		}
 
		// Collect any explicit @CachePuts
		collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
 
		// Process any collected put requests, either from @CachePut or a @Cacheable miss
		for (CachePutRequest cachePutRequest : cachePutRequests) {
			cachePutRequest.apply(cacheValue);
		}
 
		// Process any late evictions
		processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue); 
		return returnValue;
	}

因此如果我们需要自行控制缓存失效策略,就可能需要一些开发工作,具体如下。

Spring Cache 失效时间自行刷新

1:基于Spring的Cache组件进行定制,对get方法进行重写,刷新过期时间。相对简单,不难;此处不贴代码了。

2:可以使用后台线程进行定时的缓存刷新,以达到刷新时间的作用。

3:使用spring data redis模块,该模块提供对了TTL更新策略的,可以参见:org.springframework.data.redis.core.PartialUpdate

注意:

Spring对于@Cacheable注解是由spring-context提供的,spring-context提供的缓存的抽象,是一套标准而不是实现。

而PartialUpdate是由于spring-data-redis提供的,spring-data-redis是一套spring关于redis的实现方案。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 Spring @Cacheable指定失效时间实例 http://www.20zxx.cn/463663/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务