Spring?@Cacheable注解類(lèi)內(nèi)部調(diào)用失效的解決方案
@Cacheable注解類(lèi)內(nèi)部調(diào)用失效
如果你只是想使用一個(gè)輕量級(jí)的緩存方案,那么可以嘗試使用Spring cache方案。
那么在使用spring @Cacheable注解的時(shí)候,要注意,如果類(lèi)A的方法f()被標(biāo)注了@Cacheable注解,那么當(dāng)類(lèi)A的其他方法,例如:f2(),去直接調(diào)用f()的時(shí)候,@Cacheable是不起作用的,原因是@Cacheable是基于spring aop代理類(lèi),f2()屬于內(nèi)部方法,直接調(diào)用f()時(shí),是不走代理的。
舉個(gè)例子:
@Cacheable(key = "#entityType", value = "xxxCache") ? ? public List<String selectByEntityType(intentityType) { ? ? ? ? List<String> result = new ArrayList<>(); ? ? ? ? //do something ? ? ? ? return result; ? ? } public List<String> f2(){ ? //Cacheable失效,不會(huì)走緩存的 ? selectByEntityType(1); }
可以把selectByEntityType方法抽取到另外的類(lèi)中,例如:
@Service public class CacheService{ @Cacheable(key = "#entityType", value = "xxxCache") ? ? public List<String selectByEntityType(intentityType) { ? ? ? ? List<String> result = new ArrayList<>(); ? ? ? ? //do something ? ? ? ? return result; ? ? } }
這樣其他類(lèi)要使用selectByEntityType方法,只能注入CacheService,走代理。
@Cacheable注解緩存方法內(nèi)部調(diào)用
因?yàn)镾pring Cache是基于切面的(基于AOP的動(dòng)態(tài)代理實(shí)現(xiàn)的:即都在方法調(diào)用前后去獲取方法的名稱、參數(shù)、返回值,然后根據(jù)方法名稱、參數(shù)生成緩存的key(自定義的key例外),進(jìn)行緩存),所以內(nèi)部方法調(diào)用不會(huì)調(diào)用切面,導(dǎo)致緩存不生效
方法一
暴露Aop代理到ThreadLocal支持,在類(lèi)之前加@EnableAspectJAutoProxy(exposeProxy = true)
調(diào)用的時(shí)候使用((XxxService) AopContext.currentProxy()).method()調(diào)用方法
eg:
ApiBaseResponse<ApiPageResponse<RoadCongestIndexData>> apiPageResponseApiBaseResponse = ? ? ? ? ? ? ? ? ((RoadLastPageServiceImpl) AopContext.currentProxy()).queryLastPageCongestIndexData1(request);
方法二
把需要用緩存的方法單獨(dú)寫(xiě)到一個(gè)類(lèi)里面,把內(nèi)部調(diào)用變成類(lèi)間調(diào)用
RoadLastPageServiceImpl selfService = SpringContextUtil.getBean(RoadLastPageServiceImpl.class); ? ? ? ? selfService.queryLastPageCongestIndexData1(request);
方法三
類(lèi)自我注入,使用@lazy和@Autowired注解實(shí)現(xiàn)自我注入,然后使用時(shí)用注解的實(shí)例代替this調(diào)用方法。
@Lazy @Autowired private RoadLastPageServiceImpl serviceImplCache;
方法四
寫(xiě)一個(gè)工具類(lèi),使用內(nèi)部調(diào)用的時(shí)候,自己實(shí)例化一個(gè)對(duì)象,讓類(lèi)走AOP
@Component public class SpringContextUtil implements ApplicationContextAware { ? ? private static ApplicationContext applicationContext; ? ? /** ? ? ?* 實(shí)現(xiàn)ApplicationContextAware接口的回調(diào)方法,設(shè)置上下文環(huán)境 ? ? ?* ? ? ?* @param applicationContext ? ? ?*/ ? ? @Override ? ? public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ? ? ? ? SpringContextUtil.applicationContext = applicationContext; ? ? } ? ? public static ApplicationContext getApplicationContext() { ? ? ? ? return applicationContext; ? ? } ? ? /** ? ? ?* 獲取對(duì)象 ? ? ?* ? ? ?* @param name ? ? ?* @return Object ? ? ?* @throws BeansException ? ? ?*/ ? ? public static Object getBean(String name) throws BeansException { ? ? ? ? return applicationContext.getBean(name); ? ? } ? ? /** ? ? ?* 通過(guò)類(lèi)型獲取對(duì)象 ? ? ?* ? ? ?* @param t ? ? ?* ? ? ? ? ? ?對(duì)象類(lèi)型 ? ? ?* @return ? ? ?* @throws BeansException ? ? ?*/ ? ? public static <T> T getBean(Class<T> t) throws BeansException { ? ? ? ? return applicationContext.getBean(t); ? ? } }
調(diào)用的時(shí)候這么調(diào)用
RoadLastPageServiceImpl selfService = SpringContextUtil.getBean(RoadLastPageServiceImpl.class); selfService.queryLastPageCongestIndexData1(request);
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Mybatis如何解決sql中l(wèi)ike通配符模糊匹配問(wèn)題
這篇文章主要介紹了Mybatis如何解決sql中l(wèi)ike通配符模糊匹配問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Spring5源碼解析之Spring中的異步和計(jì)劃任務(wù)
本篇文章主要介紹了Spring5源碼解析之Spring中的異步和計(jì)劃任務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-10-10SpringCloud集成Eureka并實(shí)現(xiàn)負(fù)載均衡的過(guò)程詳解
這篇文章主要給大家詳細(xì)介紹了SpringCloud集成Eureka并實(shí)現(xiàn)負(fù)載均衡的過(guò)程,文章通過(guò)代碼示例和圖文講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下2023-11-11springboot+chatgpt+chatUI Pro開(kāi)發(fā)智能聊天工具的實(shí)踐
本文主要介紹了springboot+chatgpt+chatUI Pro開(kāi)發(fā)智能聊天工具的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Spring Boot啟動(dòng)及退出加載項(xiàng)的方法
這篇文章主要介紹了Spring Boot啟動(dòng)及退出加載項(xiàng)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04