zoukankan      html  css  js  c++  java
  • 【转】 Spring NoSuchBeanDefinitionException原因分析

    摘要:本文译自Eugen Paraschiv文章spring NoSuchBeanDefinitionException 原文链接: http://www.baeldung.com/spring-nosuchbeandefinitionexception 感谢Eugen Paraschiv对此所做的研究。

    概述

    在本文中,我将通过实例向你展示Spring 中org.springframework.beans.factory.NoSuchBeanDefinitionException 出现的原因。如果BeanFactory在Spring Context中没有找到bean的实例,就会抛出这个常见的异常。

    Cause: No qualifying bean of type […] found for dependency

    这个异常的出现一般是因为需要注入的bean未定义 
    有一个类BeanA.Java

    package com.csdn.training.model;
    @Component
    public class BeanA {
        @Autowired
        private BeanB beanB;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    有一个类BeanB.java

    package com.csdn.training.service;
    
    @Component
    public class BeanB {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    配置文件applicationContext.xml

    <context:component-scan base-package="com.csdn.training.model"></context:component-scan>
    • 1

    用一个测试类去启动拉起Spring容器:

    package com.csdn.test;
    
    public class AppTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            BeanA beanA = (BeanA) context.getBean("beanA");
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    自动扫描包路径缺少了BeanB,它和BeanA 不在同一路径下 
    如果依赖 IBusinessService 在Spring 上下文中没有定义,引导进程报错:No Such Bean Definition Exception.

    nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.csdn.training.service.BeanB] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
    • 1

    Spring会提示:”Expected at least 1 bean which qualifies as autowire candidate for this dependency“(依赖至少有一个备选的bean能被自动注入) 
    出现异常的原因是IBusinessService 在上下文中不存在:如果bean是通过classpath自动扫描来装配,并且IBusinessService已经正确的加上了注解(@Component,@Repository,@Service,@Controller等),也许是你没有把正确的包路径告诉Spring。

    配置文件可以如下配置:

    <context:component-scan base-package="com.csdn.training"></context:component-scan>
    • 1

    如果bean不能自动被扫描到,而手动定义却可以识别,那Bean就没有在Spring上下文中定义。

    Cause: No qualifying bean of type […] is defined

    造成这一异常的原因可能是Spring上下文中存在两个或以上该bean的定义。如果接口IService 有两个实现类 ServiceImplA 和ServiceImplB 
    接口:IService.java

    package com.csdn.training.service;
    
    public interface IService {
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    两个实现类:ServiceImplA.java

    package com.csdn.training.service;
    
    import org.springframework.stereotype.Service;
    @Service
    public class ServiceImplA implements IService {
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ServiceImplB.java

    package com.csdn.training.service;
    
    import org.springframework.stereotype.Service;
    @Service
    public class ServiceImplB implements IService {
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果BeanA 自动注入这一接口,Spring就无法分辨到底注入哪一个实现类:

    package com.csdn.training.model;
    
    import com.csdn.training.service.IService;
    @Component
    public class BeanA {    
        @Autowired
        private IService serviceImpl;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后,BeanFactory就抛出异常NoSuchBeanDefinitionException 
    Spring会提示:”expected single matching bean but found 2“(只应该匹配一个bean但是找到了多个)

    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
    No qualifying bean of type [com.csdn.training.service.IService] is defined: 
    expected single matching bean but found 2: serviceImplA,serviceImplB
    • 1
    • 2
    • 3

    上例中,有时你看到的异常信息是NoUniqueBeanDefinitionException,它是NoSuchBeanDefinitionException 它的子类,在Spring 3.2.1中,修正了这一异常,为的是和bean未定义这一异常区分开。

    nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.csdn.training.service.IService] is defined: expected single matching bean but found 2: serviceImplA,serviceImplB
    • 1

    解决这一异常可以用注解@Qualifier 来指定想要注入的bean的名字。

    package com.csdn.training.model;
    
    import com.csdn.training.service.IService;
    @Component
    public class BeanA {
        @Autowired
        @Qualifier("serviceImplA")
        private IService serviceImpl;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    修改以后,Spring就可以区分出应该注入那个bean的实例,需要注意的是ServiceImplA的默认实例名称是serviceImplA

    Cause: No Bean Named […] is defined

    当你通过具体的bean的名字去得到一个bean的实例的时候,如果Spring 没有在上下文中找到这个bean,就会抛出这个异常。

    package com.csdn.test;
    
    public class AppTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            context.getBean("beanX");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个例子中,没有一个bean被定义成 “beanX”,就会抛出如下异常: 
    Spring会提示:”No bean named XXX is defined” (没有找到一个名叫XXX的bean)

    org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'beanX' is defined at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition
    • 1

    Cause: Proxied Beans

    如果bean由JDK的动态代理机制所管理,那么代理将不会继承该bean,它只会实现与其相同的接口。因此,如果bean是通过接口注入的,就可以成功注入。如果通过其实现类注入,Spring就无法将bean实例与类关联,因为代理并不真正的继承于类。 
    出现这一原因,很有可能是因为你使用了Spring的事物,在bean上使用了注解@Transactional 
    如下,ServiceA注入了ServiceB,这两个service都使用了事物,通过实现类注入bean就不起作用了。 
    借口IService.java无变化,其实现类加上事物的注解 
    ServiceImplA.java

    package com.csdn.training.service;
    
    @Service
    @Transactional
    public class ServiceImplA implements IService {
        @Autowired
        private ServiceImplB serviceImplB;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ServiceImplB.java

    package com.csdn.training.service;
    
    @Service
    @Transactional
    public class ServiceImplB implements IService {
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果改成通过接口注入,就可以:

    ServiceImpl.java

    package com.csdn.training.service;
    
    @Service
    @Transactional
    public class ServiceImplA implements IService {
        @Autowired
        @Qualifier("serviceImplB")
        private IService serviceImplB;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结论

    本文通过几个小例子,分析了NoSuchBeanDefinitionException 用了这一异常可能出现的情形,对于我们在实际开发过程中定位错误提供了一定的参考。 
    原文为英文版,我在原文的基础上稍作改动,但又尽量保持原文的精髓,如果对译文有异议,欢迎指正。

  • 相关阅读:
    Android各版本系统源代码下载
    Android ListView从网络获取图片及文字显示
    Android 仿QQ主页面的实
    Android ListView初步
    SQLite数据库的使用
    Android ViewPager使用详解
    (转载)在Android中使用Handler和Thread线程执行后台操作
    Android常用的工具类收藏用
    IBM HACMP 系列 后期安装工作和管理任务一
    ORA02024: Database Link Not Found [ID 1058949.1]
  • 原文地址:https://www.cnblogs.com/dafanshu1996/p/6498784.html
Copyright © 2011-2022 走看看