Spring緩存穿透問題修復

發布日期:2019-10-17

?

BENWENLAIZIWANGYIYUNSHEQU。

?

BENJUQINGCHUNSHUZHENSHI,YOURULEITONGSHINAIYUANFEN。

?

發生

?

SHIQINGDEFASHENGZAIMOUTIANZAOSHANG,TIANQIZENYANGFANZHENGSHIWANGLE,ZHIJIDEDANGSHIJIANKONGPINGTAIDALIANGDESHUJUKUCUOWUBAOJING。 ZUOWEIHOUDUANKAIFA,DANGKANDAORIZHIZHONGDALIANGDEdbLIANJIEHUOQUSHIBAI,XINQINGSHIFUZADE。

KANLEXIAPEIZHIHESHIJILIANJIESHU,JINGRAN。。。MEIMAN。EN,KENENGSHITUFALIULIANG。RANERMEIDUOJIU,YIDABOBAOJINGYOUXILAI,GANJUESHIQINGMEINEIMEJIANDAN。

常規措施無果,連續數次如此,看日志發現時間有點奇怪,都是間隔5分鐘, 難道。。。緩存失效了? 看業務代碼和緩存配置,很有可能。

?

業務代碼表示

@Cacheable(value = "item_volume", key = ""item_" + #gid", unless = "#result == null") public Item queryiItem(long gid) { Optional<Item> optional = itemService.getItem(null, gid); return optional.orNull(); }

注: cache的實現用的是spring->

?

初步分析

?

MEICUO,HUANPEIZHIitem_volumeGUOQISHIJIAN5FENZHONG,YEJIUSHISHUO,DANGHUANCUNGUOQIHOU,CISHIRUGUOYOUDALIANGQINGQIU,NEIMEZHEXIEQINGQIUDOUHUIYINWEIHUANCUNSHIXIAOERQINGQIUSHUJUKU。 KANQILAIQINGXINGSHIZHEYANGDE:

?

?

?

RUGUOJIASHECHENGLI,NEIJIUSHIspringZAICHULIHUANCUNDESHIHOU,RUGUOMEIYOUMINGZHONG,ZHIJIECHUANTOUZHIXINGSHIJICAOZUO(dbCHAXUN),YEJIUSHISHUO,ZHONGJIANSHIBUJIASUODE。

ZHEYANGJIUJIESHITONGLE,DANZHESHIbugMA,HUANSHIspringRENWEISHIGEfeature, ZHESHIGEWENTI。

?

發展

?

Talk is cheap, show me the code. --linuxZHIDIE

關鍵是,code在哪。又得上套路了:套路: 既然是AOP,找找Advice。 最直接能想到,就是在spring中找所有Advice接口的繼承樹,然而數量太多,逐個尋找驗證實在是耗時。

SHUXIspringSHIWUDETONGXUEYINGGAINENGXIANGDAO@TransactionalDEAdviceSHITransactionInterceptor,NEIMEcacheSHIFOUDUIYINGDUIYIGECacheInterceptorNI。YIKAN,HUANZHENYOU,NEIJIUHAOBANLE,ERQIEKANQIJIUSHIYAOZHAODE。

?

修改代碼

SHUNZHUCacheInterceptorDEinvokeFANGFA,DINGWEIDAOCacheAspectSupport.execute,KANDAIMASHIXIAN,QUESHIMEIJIASUO,NEIJIUJIAGESUOBAI:

private Lock lock = new ReentrantLock(); //execute中部分代碼 lock.lock(); try { result = findCachedItem(contexts.get(CacheableOperation.class)); if (result == null) { result = new SimpleValueWrapper(invokeOperation(invoker)); } collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests); for (CachePutRequest cachePutRequest : cachePutRequests) { cachePutRequest.apply(result.get()); } processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get()); } finally { lock.unlock(); }

QIZHONG,lockXIANGGUANWEIXINJIABUFEN。

?

高潮

?

DAIMASHIGAIHAOLE,ZENMESHENGXIAONI。HUANDEHUITOUKANKANCacheInterceptorSHIRUHEZHURUDE,YEBUNANZHAODAO:

那就寫個類 MyCacheAspectSupport.java.txt 來代替CacheInterceptor,然后注入。這里又會用到一些 套路:bean覆蓋套路:beanname規則 等。

FANGFA1:YOUYUProxyCachingConfigurationMEIYOUZHIDINGAdviceDEname,NEIJIUYONGMORENDE:

<bean id="errorHandler" /> <bean name="org.springframework.cache.interceptor.CacheInterceptor#0" p:errorHandler-ref="errorHandler" p:cacheManager-ref="cacheManager"/>

YANZHENGXIA,KEYIGONGZUO,RANERZONGJUEDENALIBUDUI,EN,RUGUOYOUDUOGEbean。。。

FANGFA2: ZHUYIDAOProxyCachingConfigurationZHONGAdvisorDEnameLEMA,NEIJIUDINGYIAdvisor:

<bean id="errorHandler" /> <bean name="myCacheAdvice" p:errorHandler-ref="errorHandler" p:cacheManager-ref="cacheManager"/> <bean id="annotationCacheOperationSource" /> <bean name="org.springframework.cache.config.internalCacheAdvisor" p:adviceBeanName="myCacheAdvice" p:cacheOperationSource-ref="annotationCacheOperationSource" />

YANZHENGXIA,KEYIGONGZUO。QISHIHUANKEYIYOU3:

FANGFA3:SHIXIANBeanPostProcessorJIEKOU

@Autowired private MyCacheAspectSupport mycacheAdvice; @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (CacheInterceptor.class.isAssignableFrom(bean.getClass())) { return mycacheAdvice; } return bean; }

YANZHENGXIA,KEYIGONGZUO。

?

結尾

?

HAOLE,WENTIJIEJUE,CELEXIAXINGNENGYEMEITAIDAXIAJIANG(<1%,CHANGJINGBUTONG,JINGONGCANKAO),ZHONGYUYOUKEYIYUKUAIDESHIYONGCacheableDENGZHUJIELE。

springHEXIANGGUANYANSHENGYONGYOUXIANGDANGDADEDAIMALIANG,HAOZAIYOUHENDUOTAOLUDOUSHITONGYONGDE,LIYONGZHEXIETAOLUNENGRANGWOMENJIEJUEWENTISHIBANGONGBEI。

ZHU: WENZHONGspringBANBENWEI4.2.6.RELEASE

?

?

BENWENLAIZIWANGYIYUNSHEQU,JINGZUOZHEWANGDAXISHOUQUANFABU。

原文:Spring緩存穿透問題修復