1. 개요

이 기사에서 우리는 Spring org.springframework.beans.factory.NoSuchBeanDefinitionException에 대해 논의하고 있습니다. 이것은 단순히 Spring 컨텍스트에 정의되지 않은 빈 을 해결하려고 할 때 BeanFactory에서 throw되는 일반적인 예외 입니다.

이 문제의 가능한 원인과 사용 가능한 솔루션을 설명합니다.

그리고 물론, 예외는 예상하지 못한 경우에 발생합니다. Spring의 예외 및 솔루션의 전체 List을 살펴보십시오 .

2. 원인: 의존성에 대해 […] 유형의 적격 Bean을 찾을 수 없습니다.

이 예외의 가장 일반적인 원인은 정의되지 않은 빈을 주입하려는 것입니다. 예를 들어 – BeanB 는 공동 작업자 – BeanA 에서 연결 중입니다 .

@Component
public class BeanA {

    @Autowired
    private BeanB dependency;
    //...
}

이제 의존성( BeanB) 이 Spring 컨텍스트에 정의되지 않은 경우 부트스트랩 프로세스는 이러한 빈 정의 예외 없이 실패 합니다 .

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.baeldung.packageB.BeanB]
  found for dependency: 
expected at least 1 bean which qualifies as
  autowire candidate for this dependency. 
Dependency annotations: 
  {@org.springframework.beans.factory.annotation.Autowired(required=true)}

그 이유는 분명 Spring으로 표시됩니다 : " 예상 적어도 1 Bean이 의존성에 대한 자동으로 묶어 후보로하는 자격을 "

BeanB 가 컨텍스트에 존재하지 않을 수 있는 한 가지 이유 - 빈이 클래스 경로 스캐닝에 의해 자동으로 선택되고 BeanB 가 빈으로 올바르게 어노테이션 처리된 경우 ( @Component , @Repository , @Service , @Controller 등) - 그럴 수 있기 때문입니다. Spring에서 스캔하지 않는 패키지에 정의됨 :

package com.baeldung.packageB;
@Component
public class BeanB { ...}

클래스 경로 스캔은 다음과 같이 구성할 수 있습니다.

@Configuration
@ComponentScan("com.baeldung.packageA")
public class ContextWithJavaConfig {
    ...
}

Bean이 자동으로 대신 검색되지 않으면 수동으로 정의 하고 BeanB는 단순히 현재 Spring 컨텍스트에 정의되어 있지 않습니다.

3. 원인: […]의 필드 […]에는 찾을 수 없는 […] 유형의 Bean이 필요했습니다.

위의 시나리오에 대한 Spring Boot 애플리케이션에서는 다른 메시지가 표시됩니다.

의이 같은 예를 보자  BeanB이 에 연결되어 BeanA  하지만이 정의되지 않은 것을 :

@Component
public class BeanA {
	
    @Autowired
    private BeanB dependency;
    //...
}

이 간단한 애플리케이션을 실행하려고 하면 BeanA 를 로드하려고 합니다 .

@SpringBootApplication
public class NoSuchBeanDefinitionDemoApp {

    public static void main(String[] args) {
        SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args);
    }
}

다음 오류 메시지와 함께 응용 프로그램이 시작되지 않습니다.

***************************
APPLICATION FAILED TO START
***************************

Description:

Field dependency in com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found.


Action:

Consider defining a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.

여기에서  com.baeldung.springbootmvc.nosuchbeandefinitionexceptionBeanA , BeanB 및  NoSuchBeanDefinitionDemoApp 용 패키지입니다  .

이 예제의 스니펫은 이 Github 프로젝트 에서 찾을 수 있습니다 .

4. 원인: […] 유형의 적격 Bean이 정의되지 않았습니다.

예외의 또 다른 원인은 컨텍스트에 하나가 아닌 두 개의 빈 정의가 존재하기 때문입니다. 예를 들어 인터페이스 IBeanBBeanB1BeanB2 라는 두 개의 빈으로 구현되는 경우 :

@Component
public class BeanB1 implements IBeanB {
    //
}
@Component
public class BeanB2 implements IBeanB {
    //
}

이제 BeanA가 이 인터페이스를 자동 연결하면 Spring은 두 가지 구현 중 어느 것을 주입할지 알 수 없습니다.

@Component
public class BeanA {

    @Autowired
    private IBeanB dependency;
    ...
}

그리고 다시 BeanFactory에 의해 NoSuchBeanDefinitionException 이 발생합니다 .

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type 
  [com.baeldung.packageB.IBeanB] is defined: 
expected single matching bean but found 2: beanB1,beanB2

마찬가지로 Spring은 배선 실패의 이유를 "예상 단일 일치하는 bean이지만 2를 찾았습니다"로 명확하게 나타냅니다 .

공지 사항, 그러나,이 경우, 슬로우 정확한 예외는 아니다 NoSuchBeanDefinitionException이 -하지만 서브 클래스 NoUniqueBeanDefinitionException . 이 새로운 예외는 Spring 3.2.1도입 되었습니다. 바로 이러한 이유로 빈 정의가 발견되지 않은 원인과 컨텍스트에서 여러 정의가 발견되는 원인을 구별하기 위한 것입니다.

이 변경 이전에 위의 예외는 다음과 같습니다.

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: 
expected single matching bean but found 2: beanB1,beanB2

이 문제에 대한 한 가지 해결책은 연결하려는 빈의 이름을 정확히 지정 하기 위해 @Qualifier 어노테이션 을 사용하는 것입니다.

@Component
public class BeanA {

    @Autowired
    @Qualifier("beanB2")
    private IBeanB dependency;
    ...
}

- 이제 Spring은 빈의 주입 결정하기에 충분한 정보가 BeanB1 또는 BeanB2을 (의 기본 이름 BeanB2가 있다 beanB2 ).

5. 원인: […]라는 이름의 빈이 정의되어 있지 않습니다.

NoSuchBeanDefinitionException이이 정의되지 않은 Bean이되는 경우도 발생 될 수 있습니다 이름으로 요구 Spring 컨텍스트에서 :

@Component
public class BeanA implements InitializingBean {

    @Autowired
    private ApplicationContext context;

    @Override
    public void afterPropertiesSet() {
        context.getBean("someBeanName");
    }
}

이 경우 "someBeanName"에 대한 빈 정의가 없으므로 다음 예외가 발생합니다.

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No bean named 'someBeanName' is defined

다시, Spring은 실패의 이유를 명확하고 간결하게 나타냅니다. " X라는 이름의 빈이 정의되어 있지 않습니다 .".

6. 원인: 프록시 빈

컨텍스트의 빈이 JDK 동적 프록시 메커니즘을 사용 하여 프록시되면 프록시는 대상 빈을 확장하지 않습니다 (그러나 동일한 인터페이스를 구현함).

이 때문에 빈이 인터페이스에 의해 주입되면 올바르게 연결됩니다. 그러나 빈이 실제 클래스에 의해 주입되면 Spring은 클래스와 일치하는 빈 정의를 찾지 못합니다. 프록시는 실제로 클래스를 확장합니다.

빈이 프록시될 수 있는 매우 일반적인 이유는 Spring 트랜잭션 지원 , 즉 @Transactional 로 어노테이션이 달린 빈입니다 .

예를 들어 ServiceAServiceB를 주입 하고 두 서비스가 모두 트랜잭션인 경우 클래스 정의에 의한 주입 은 작동하지 않습니다.

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private ServiceB serviceB;
    ...
}

@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

이번에 는 인터페이스에 의해 올바르게 주입되는 동일한 두 서비스 는 괜찮을 것입니다.

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private IServiceB serviceB;
    ...
}

@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

7. 결론

이 예제에서는 일반적인 NoSuchBeanDefinitionException에 대한 가능한 원인의 예를 논의 했으며 실제로 이러한 예외를 처리하는 방법에 중점을 둡니다.

이러한 모든 예외 예제의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다. 이것은 Eclipse 기반 프로젝트이므로 가져오기 및 그대로 실행하기 쉬워야 합니다.

마지막으로 Spring 의 전체 예외 및 솔루션 List은 책갈피에 좋은 리소스가 될 수 있습니다.

Generic footer banner