欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

解决ApplicationContext获取不到Bean的问题,

来源: javaer 分享于  点击 39735 次 点评:59

解决ApplicationContext获取不到Bean的问题,


目录
  • 开发环境遇到报错
  • 部署环境
  • 问题代码
  • 解决方案
  • 修复代码
  • 总结

开发环境遇到报错

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'XXXXX' available

现将原问题代码简化抽出分析。

部署环境

  • springboot版本:1.x
  • java:1.8
  • 其他:略

问题代码

service层

  • 接口:
public interface ErrorBeanService {

    void transactionalMethod();

    void callMethod();
}
  • 实现类:
@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使得内部调用事务注解生效,但在获取bean时报错NoSuchBeanDefinitionException异常,报错如下:

排除了包扫描和beanName问题,看上述报错倒数第四行报错:

org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)

由于使用了事物注解(AOP)从而使用了动态代理,该环境使用的是JDK的动态代理机制,那么代理不会继承而是使用实现接口。

所以这个bean是通过接口注入的,就无法通过接口的实例与bean的实例关联。

ps:

  • Springboot 1.x AOP默认还是使用 JDK 动态代理的
  • 如果目标对象实现了接口默认采用JDK动态代理 (可强制改为CGLIB)
  • 如果目标对象没有实现接口默认采用CGLIB动态代理

解决方案

  • 升级SpringBoot版本为2.x,AOP默认使用CGLIB实现。
  • properties配置文件增加:spring.aop.proxy-target-class=true ## 强制使用CGLIB代理
  • 使用applicationContext.getBean的重载方法获取对应的bean

修复代码

为了探求transactional注解是否生效,现增加AOP 切面类模拟事物。

@Aspect
@Configuration
public class AopConfig {

    /**
     * 增强transactionalMethod方法 模拟transational注解
     */
    @Pointcut("execution(* com.example.springbootdemo.error.test.ErrorBeanServiceImpl.transactionalMethod())")
    public void executeAdvice() {
    }

    /**
     * 环绕增强
     */
    @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;
    }

}

去除事务注解:

@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();
    }

上述三种方式最终输出结果:

aroundAdvice before proceed
transactionalMethod run ~ 
aroundAdvice after proceed

体悟:八股文还是有用的~

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持3672js教程。

您可能感兴趣的文章:
  • Spring中的ApplicationContext与BeanFactory详解
  • BeanFactory与ApplicationContext的区别示例解析
  • Spring容器-BeanFactory和ApplicationContext使用详解
  • 一文学透ApplicationContext继承接口功能及与BeanFactory区别
  • 关于接口ApplicationContext中的getBean()方法使用
相关栏目:

用户点评