解決ApplicationContext獲取不到Bean的問(wèn)題
開發(fā)環(huán)境遇到報(bào)錯(cuò)
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'XXXXX' available
現(xiàn)將原問(wèn)題代碼簡(jiǎn)化抽出分析。
部署環(huán)境
- springboot版本:1.x
- java:1.8
- 其他:略
問(wèn)題代碼
service層
- 接口:
public interface ErrorBeanService { void transactionalMethod(); void callMethod(); }
- 實(shí)現(xiàn)類:
@Service("errorBeanServiceImpl") public class ErrorBeanServiceImpl implements ErrorBeanService{ private ApplicationContext applicationContext; @Autowired public void setApplicationContext(ApplicationContext applicationContext){ this.applicationContext = applicationContext; } @Transactional(rollbackFor = Exception.class) public void transactionalMethod() { System.out.println("transactionalMethod run ~ "); } public void callMethod() { // Transactional注解失效 // transactionalMethod(); // 使用applicationContext獲取到bean 使事物注解生效 applicationContext.getBean(ErrorBeanServiceImpl.class).transactionalMethod(); // 報(bào)錯(cuò)行 } }
contro層:
@RestController @RequestMapping("/error") public class ErrorController { @Autowired private ErrorBeanService errorBeanService; @RequestMapping(value = "/errorBean", method = RequestMethod.GET) public void errorBean() { errorBeanService.callMethod(); } }
查看報(bào)錯(cuò)行代碼,使用了applicationContext.getBean的方式獲取bean使得內(nèi)部調(diào)用事務(wù)注解生效,但在獲取bean時(shí)報(bào)錯(cuò)NoSuchBeanDefinitionException異常,報(bào)錯(cuò)如下:
排除了包掃描和beanName問(wèn)題,看上述報(bào)錯(cuò)倒數(shù)第四行報(bào)錯(cuò):
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
由于使用了事物注解(AOP)從而使用了動(dòng)態(tài)代理,該環(huán)境使用的是JDK的動(dòng)態(tài)代理機(jī)制,那么代理不會(huì)繼承而是使用實(shí)現(xiàn)接口。
所以這個(gè)bean是通過(guò)接口注入的,就無(wú)法通過(guò)接口的實(shí)例與bean的實(shí)例關(guān)聯(lián)。
ps:
- Springboot 1.x AOP默認(rèn)還是使用 JDK 動(dòng)態(tài)代理的
- 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口默認(rèn)采用JDK動(dòng)態(tài)代理 (可強(qiáng)制改為CGLIB)
- 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口默認(rèn)采用CGLIB動(dòng)態(tài)代理
解決方案
- 升級(jí)SpringBoot版本為2.x,AOP默認(rèn)使用CGLIB實(shí)現(xiàn)。
- properties配置文件增加:spring.aop.proxy-target-class=true ## 強(qiáng)制使用CGLIB代理
- 使用applicationContext.getBean的重載方法獲取對(duì)應(yīng)的bean
修復(fù)代碼
為了探求transactional注解是否生效,現(xiàn)增加AOP 切面類模擬事物。
@Aspect @Configuration public class AopConfig { /** * 增強(qiáng)transactionalMethod方法 模擬transational注解 */ @Pointcut("execution(* com.example.springbootdemo.error.test.ErrorBeanServiceImpl.transactionalMethod())") public void executeAdvice() { } /** * 環(huán)繞增強(qiáng) */ @Around("executeAdvice()") public Object aroundAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable { System.out.println("aroundAdvice before proceed"); Object obj = thisJoinPoint.proceed(); System.out.println("aroundAdvice after proceed"); return obj; } }
去除事務(wù)注解:
@Service("errorBeanServiceImpl") public class ErrorBeanServiceImpl implements ErrorBeanService{ private ApplicationContext applicationContext; @Autowired public void setApplicationContext(ApplicationContext applicationContext){ this.applicationContext = applicationContext; } public void transactionalMethod() { System.out.println("transactionalMethod run ~ "); } public void callMethod() { applicationContext.getBean(ErrorBeanServiceImpl.class).transactionalMethod(); } }
- 升級(jí)SpringBoot版本為2.x 略
- 配置配置文件 略
- 修改callMethod方法使用getBean的重載方法
<T> T getBean(String var1, Class<T> var2) throws BeansException;
代碼如下:
public void callMethod() { // applicationContext.getBean(ErrorBeanServiceImpl.class).transactionalMethod(); applicationContext.getBean("errorBeanServiceImpl", ErrorBeanService.class).transactionalMethod(); }
上述三種方式最終輸出結(jié)果:
aroundAdvice before proceed
transactionalMethod run ~
aroundAdvice after proceed
體悟:八股文還是有用的~
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot集成JWT實(shí)現(xiàn)登錄注冊(cè)的示例代碼
本文主要介紹了Springboot集成JWT實(shí)現(xiàn)登錄注冊(cè)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06SpringMvc+POI處理excel表數(shù)據(jù)導(dǎo)入
這篇文章主要為大家詳細(xì)介紹了SpringMvc+POI處理excel表數(shù)據(jù)導(dǎo)入,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫(kù)切換操作
這篇文章主要介紹了Spring-基于Spring使用自定義注解及Aspect實(shí)現(xiàn)數(shù)據(jù)庫(kù)切換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09使用Spring AntPathMatcher的doMatch方法
這篇文章主要介紹了使用Spring AntPathMatcher的doMatch方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java實(shí)戰(zhàn)項(xiàng)目 圖書管理系統(tǒng)
這篇文章主要介紹了使用java SSM jsp mysql maven設(shè)計(jì)實(shí)現(xiàn)的精品圖書管理系統(tǒng),是一個(gè)很好的實(shí)例,對(duì)大家的學(xué)習(xí)和工作具有借鑒意義,建議收藏一下2021-09-09