




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第一次排查@CacheEvict注解失效的經(jīng)歷及解決publicObjectinvoke(finalMethodInvocationinvocation)throwsThrowable{
Methodmethod=invocation.getMethod();
CacheOperationInvokeraopAllianceInvoker=()-{
try{
returnceed();
catch(Throwableex){
thrownewCacheOperationInvoker.ThrowableWrapper(ex);
try{
returnexecute(aopAllianceInvoker,invocation.getThis(),method,invocation.getArguments());
catch(CacheOperationInvoker.ThrowableWrapperth){
throwth.getOriginal();
進(jìn)入execute方法
protectedObjectexecute(CacheOperationInvokerinvoker,Objecttarget,Methodmethod,Object[]args){
//Checkwhetheraspectisenabled(tocopewithcaseswheretheAJispulledinautomatically)
if(this.initialized){
ClasstargetClass=getTargetClass(target);
CacheOperationSourcecacheOperationSource=getCacheOperationSource();
if(cacheOperationSource!=null){
CollectionCacheOperationoperations=cacheOperationSource.getCacheOperations(method,targetClass);
if(!CollectionUtils.isEmpty(operations)){
returnexecute(invoker,method,
newCacheOperationContexts(operations,method,args,target,targetClass));
returninvoker.invoke();
cacheOperationSource記錄系統(tǒng)中所有使用了緩存的方法,cacheOperationSource.getCacheOperations(method,targetClass)能獲取deleteByTaskId()方法緩存元數(shù)據(jù),然后執(zhí)行execute()方法
@Nullable
privateObjectexecute(finalCacheOperationInvokerinvoker,Methodmethod,CacheOperationContextscontexts){
//Specialhandlingofsynchronizedinvocation
if(contexts.isSynchronized()){
CacheOperationContextcontext=contexts.get(CacheableOperation.class).iterator().next();
if(isConditionPassing(context,CacheOperationExpressionEvaluator.NO_RESULT)){
Objectkey=generateKey(context,CacheOperationExpressionEvaluator.NO_RESULT);
Cachecache=context.getCaches().iterator().next();
try{
returnwrapCacheValue(method,cache.get(key,()-unwrapReturnValue(invokeOperation(invoker))));
catch(Cache.ValueRetrievalExceptionex){
//TheinvokerwrapsanyThrowableinaThrowableWrapperinstancesowe
//canjustmakesurethatonebubblesupthestack.
throw(CacheOperationInvoker.ThrowableWrapper)ex.getCause();
else{
//Nocachingrequired,onlycalltheunderlyingmethod
returninvokeOperation(invoker);
//Processanyearlyevictions
processCacheEvicts(contexts.get(CacheEvictOperation.class),true,
CacheOperationExpressionEvaluator.NO_RESULT);
//Checkifwehaveacacheditemmatchingtheconditions
Cache.ValueWrappercacheHit=findCachedItem(contexts.get(CacheableOperation.class));
//Collectputsfromany@Cacheablemiss,ifnocacheditemisfound
ListCachePutRequestcachePutRequests=newLinkedList();
if(cacheHit==null){
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT,cachePutRequests);
ObjectcacheValue;
ObjectreturnValue;
if(cacheHit!=nullcachePutRequests.isEmpty()!hasCachePut(contexts)){
//Iftherearenoputrequests,justusethecachehit
cacheValue=cacheHit.get();
returnValue=wrapCacheValue(method,cacheValue);
else{
//Invokethemethodifwedon'thaveacachehit
returnValue=invokeOperation(invoker);
cacheValue=unwrapReturnValue(returnValue);
//Collectanyexplicit@CachePuts
collectPutRequests(contexts.get(CachePutOperation.class),cacheValue,cachePutRequests);
//Processanycollectedputrequests,eitherfrom@CachePutora@Cacheablemiss
for(CachePutRequestcachePutRequest:cachePutRequests){
cachePutRequest.apply(cacheValue);
//Processanylateevictions
processCacheEvicts(contexts.get(CacheEvictOperation.class),false,cacheValue);
returnreturnValue;
這里大致過(guò)程是:
先執(zhí)行beforInvokeEvict----執(zhí)行數(shù)據(jù)庫(kù)delete操作---執(zhí)行CachePut操作----執(zhí)行afterInvokeEvict
我們的注解是方法調(diào)用后再使緩存失效,直接所以有效的操作應(yīng)在倒數(shù)第2行
privatevoidperformCacheEvict(
CacheOperationContextcontext,CacheEvictOperationoperation,@NullableObjectresult){
Objectkey=null;
for(Cachecache:context.getCaches()){
if(operation.isCacheWide()){
logInvalidating(context,operation,null);
doClear(cache);
else{
if(key==null){
key=generateKey(context,result);
logInvalidating(context,operation,key);
doEvict(cache,key);
這里通過(guò)context.getCaches()獲取到name為taskParamsCache的緩存
然后generateKey生成key,注意這里,發(fā)現(xiàn)生成的key是com.xxx.xxx.atomic.impl.xxxxdeleteByTaskId982,但是緩存中的key卻是com.xxx.xxx.atomic.impl.xxxxselectByTaskId982,下面調(diào)用的doEvict(cache,key)方法不再跟進(jìn)了,就是從cache中移除key對(duì)應(yīng)值。明顯這里key對(duì)應(yīng)不上的,這也是導(dǎo)致@CacheEvict沒(méi)有生效的原因。
小結(jié)一下
我還是太大意了,當(dāng)時(shí)看了注解@CacheEvict的對(duì)key的注釋:
大意就是如果沒(méi)有指定key,那就會(huì)使用方法所有參數(shù)生成一個(gè)key,明顯com.xxx.xxx.atomic.impl.xxxxselectByTaskId982是方法名+參數(shù),可是你沒(méi)說(shuō)把方法名還加上了啊,說(shuō)好的只用參數(shù)呢,哈哈,這個(gè)bug是我使用不當(dāng)引出的,很多人不會(huì)犯這種低級(jí)錯(cuò)誤。
解決辦法就是使用SpEL明確定義key
@Cacheable(value="taskParamsCache",key="#taskId")
ListTaskParamsselectByTaskId(LongtaskId);
//...
//...
@CacheEvict(value="taskParamsCache",key="#taskId")
intdeleteByTaskId(LongtaskId);
說(shuō)說(shuō)spring全家桶中@CacheEvict無(wú)效情況
@CacheEvict(value=“test”,allEntries=true)
1、使用@CacheEvict注解的方法必須是controller層直接調(diào)用,service里間接調(diào)用不生效。
2、原因是因?yàn)閗ey值跟你查詢方法的key值不統(tǒng)一,所以導(dǎo)致緩存并沒(méi)有清除
3、把@CacheEvict的方法和@Cache的方法放到一個(gè)java文件中寫,他倆在兩個(gè)java文件的話,會(huì)導(dǎo)致@CacheEvict失效。
4、返回值必須設(shè)置為void
@CacheEvictannotation
Itisimportanttonotethatvoidmethodscanbeusedwith@CacheEvict
5、@CacheEvict必須作用在走代理的方法上
在使用Spring@CacheEvict注解的時(shí)候,要注意,如
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 網(wǎng)絡(luò)工程師的未來(lái)發(fā)展方向試題及答案
- 西方國(guó)家政治外交中的人權(quán)問(wèn)題試題及答案
- 經(jīng)濟(jì)政策與科技創(chuàng)新試題及答案
- 西方選舉制度的演變?cè)囶}及答案
- 深度分析西方國(guó)家的政治演變?cè)囶}及答案
- 深入解析四級(jí)軟件測(cè)試工程師典型試題及答案
- 數(shù)據(jù)庫(kù)設(shè)計(jì)在2025年軟件設(shè)計(jì)師考試中的試題及答案
- 機(jī)電工程考試難點(diǎn)透析與試題及答案
- 公共政策對(duì)未來(lái)就業(yè)的影響試題及答案
- 2025年仿制藥一致性評(píng)價(jià)對(duì)醫(yī)藥市場(chǎng)政策環(huán)境分析報(bào)告
- 2024年重慶高考化學(xué)試題卷(含答案解析)
- 2023年不動(dòng)產(chǎn)登記代理人《不動(dòng)產(chǎn)登記代理實(shí)務(wù)》沖刺備考200題(含詳解)
- 畜產(chǎn)品市場(chǎng)營(yíng)銷策劃方案
- GB/T 18852-2020無(wú)損檢測(cè)超聲檢測(cè)測(cè)量接觸探頭聲束特性的參考試塊和方法
- ZJUTTOP100理工類學(xué)術(shù)期刊目錄(2018年版)
- F0值計(jì)算公式自動(dòng)
- 《全國(guó)統(tǒng)一建筑工程基礎(chǔ)定額河北省消耗量定額》宣貫資料
- 道路交通事故現(xiàn)場(chǎng)勘查課件
- 門店電表記錄表
- 組態(tài)王雙機(jī)熱備
- 綠地圖繪制指南
評(píng)論
0/150
提交評(píng)論