@configuration@enablecachingpublic class rediscacheconfig { @bean public rediscachemanagerbuildercustomizer rediscachemanagerbuildercustomizer() { return (builder) -> { for (map.entry<string, duration> entry : rediscachename.getcachemap().entryt()) { 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.ofconds(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.toconds(15)) .put(cachenames.cache_30mins, timeunit.minutes.toconds(30)) .put(cachenames.cache_60mins, timeunit.minutes.toconds(60)) .put(cachenames.cache_180mins, timeunit.minutes.toconds(180)).build(); // spring cache是根据cache name查找缓存过期时长的,如果找不到,则使用默认值 cachemanager.tdefaultexpiration(timeunit.minutes.toconds(30)); cachemanager.texpires(expires); } } @cacheable(key = "key", cachenames = cachenames.cache_15mins) public string demo2(string key) { return "abc" + key; }
之前对spring缓存的理解是每次设置缓存之后,重复请求会刷新缓存时间,但是问题排查阅读源码发现,跟自己的理解大相径庭。所有的你以为都仅仅是你以为!!!!
目前项目使用的spring缓存,主要是cachemanager、cache以及@cacheable注解,spring现有的缓存注解暑假里的新鲜事作文无法单独设置每一个注解的失效时间,spring官方给的解释:spring cache是一个抽象而不是一个缓存实现方案。
因此对于缓存失效时间(ttl)的策略依赖于底层缓存中间件,官方给举例:concurrentmap是不支持失效时间的,而redis是支持失效时间的。
spring缓存注解@cacheable底层的cachemanager与cache如果使用redis方案的话,首次设置缓存数据之后,每次重复请求相同方法读取缓存并不会刷新失效时间,这是spring的默认行为(受一些缓存影响,一直以为每次读缓存也会刷新缓存失效时间)。
可以参见源码:
org.springframework.cache.interceptor.cacheaspectsupport#execute(org.springframework.cache.interceptor.cacheoperationinvoker, java.lang.reflect.method, org.springfram并集和交集的区别ework.cache.interceptor.cacheaspectsupport.cacheoperationcontexts)
private object execute(final cacheoperationinvoker invoker, method method, cacheoperationcontexts contexts) {// special handling of synchronized invocationif (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.getcau();}}el {// no caching required, only call the underlying methodreturn invokeoperation(invoker);}} // process any early evictionsprocesscacheevicts(contexts.get(cacheevictoperation.class), true,cacheoperationexpressionevaluator.no_result); // check if we have a cached item matching the conditionscache.valuewrapper cachehit = findcacheditem(contexts.get(cacheableoperation.class)); // collect puts from any @cacheable miss, if no cached item is foundlist<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 u the cache hitcachevalue = cachehit.get();returnvalue = wrapcachevalue(method, cachevalue);}el {// invoke the method if we don't have a cache hitreturnvalue = invokeoperation(invoker);cachevalue = unwrapreturnvalue(returnvalue);} // collect any explicit @cacheputscollectputrequests(contexts.get(cacheputoperation.class), cachevalue, cacheputrequests); // process any collected put requests, either from @cacheput or a @cacheable missfor (cacheputrequest cacheputrequest : cacheputrequests国民教育) {cacheputrequest.apply假如我是武松(cachevalue);} // process any late evictionsprocesscacheevicts(contexts.get(cacheevictoperation.class), fal, cachevalue); return returnvalue;}
因此如果我们需要自行控制缓存失效策略,就可能需要一些开发工作,具体如下。
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的实现方案。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。
本文发布于:2023-04-04 05:12:23,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/cc00cfa11125415cfbc1bfeaf9b88292.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:Spring @Cacheable指定失效时间实例.doc
本文 PDF 下载地址:Spring @Cacheable指定失效时间实例.pdf
留言与评论(共有 0 条评论) |