一次排查@CacheEvict注解失效的經(jīng)歷及解決_第1頁(yè)
一次排查@CacheEvict注解失效的經(jīng)歷及解決_第2頁(yè)
一次排查@CacheEvict注解失效的經(jīng)歷及解決_第3頁(yè)
一次排查@CacheEvict注解失效的經(jīng)歷及解決_第4頁(yè)
一次排查@CacheEvict注解失效的經(jīng)歷及解決_第5頁(yè)
已閱讀5頁(yè),還剩3頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論