解決ApplicationContext獲取不到Bean的問題
開發(fā)環(huán)境遇到報錯
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'XXXXX' available
現(xiàn)將原問題代碼簡化抽出分析。
部署環(huán)境
- springboot版本:1.x
- java:1.8
- 其他:略
問題代碼
service層
- 接口:
public interface ErrorBeanService {
void transactionalMethod();
void callMethod();
}
- 實現(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(); // 報錯行
}
}
contro層:
@RestController
@RequestMapping("/error")
public class ErrorController {
@Autowired
private ErrorBeanService errorBeanService;
@RequestMapping(value = "/errorBean", method = RequestMethod.GET)
public void errorBean() {
errorBeanService.callMethod();
}
}
查看報錯行代碼,使用了applicationContext.getBean的方式獲取bean使得內(nèi)部調(diào)用事務(wù)注解生效,但在獲取bean時報錯NoSuchBeanDefinitionException異常,報錯如下:

排除了包掃描和beanName問題,看上述報錯倒數(shù)第四行報錯:
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
由于使用了事物注解(AOP)從而使用了動態(tài)代理,該環(huán)境使用的是JDK的動態(tài)代理機(jī)制,那么代理不會繼承而是使用實現(xiàn)接口。
所以這個bean是通過接口注入的,就無法通過接口的實例與bean的實例關(guān)聯(lián)。
ps:
- Springboot 1.x AOP默認(rèn)還是使用 JDK 動態(tài)代理的
- 如果目標(biāo)對象實現(xiàn)了接口默認(rèn)采用JDK動態(tài)代理 (可強(qiáng)制改為CGLIB)
- 如果目標(biāo)對象沒有實現(xiàn)接口默認(rèn)采用CGLIB動態(tài)代理
解決方案
- 升級SpringBoot版本為2.x,AOP默認(rèn)使用CGLIB實現(xiàn)。
- properties配置文件增加:spring.aop.proxy-target-class=true ## 強(qiáng)制使用CGLIB代理
- 使用applicationContext.getBean的重載方法獲取對應(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();
}
}
- 升級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é)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實現(xiàn)爬蟲給App提供數(shù)據(jù)(Jsoup 網(wǎng)絡(luò)爬蟲)
這篇文章主要介紹了Java實現(xiàn)爬蟲給App提供數(shù)據(jù),即Jsoup 網(wǎng)絡(luò)爬蟲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01
使用java的HttpClient實現(xiàn)多線程并發(fā)
這篇文章主要介紹了使用java的HttpClient實現(xiàn)多線程并發(fā)的相關(guān)資料,需要的朋友可以參考下2016-09-09
SpringBoot使用CORS解決無法跨域訪問問題的具體步驟
跨域問題指的是不同站點之間,使用 ajax 無法相互調(diào)用的問題,跨域問題本質(zhì)是瀏覽器的一種保護(hù)機(jī)制,它的初衷是為了保證用戶的安全,防止惡意網(wǎng)站竊取數(shù)據(jù),本文給大家介紹了SpringBoot使用CORS解決無法跨域訪問問題的具體步驟,需要的朋友可以參考下2025-05-05

