prosource

NoSuch Bean 정의란?예외 사항 및 수정 방법은 무엇입니까?

probook 2023. 10. 25. 23:23
반응형

NoSuch Bean 정의란?예외 사항 및 수정 방법은 무엇입니까?

에 대해 다음과 같이 설명해주시기 바랍니다.NoSuchBeanDefinitionException스프링에서의 예외:

  • 그것은 무엇을 뜻하나요?
  • 어떤 조건으로 던지나요?
  • 어떻게 하면 막을 수 있을까요?

이 게시물은 발생에 대한 종합적인 Q&A를 목적으로 작성되었습니다.NoSuchBeanDefinitionException스프링을 사용하는 응용 프로그램에서.

설명의 자바독은

a일 때 예외가 발생했습니다.BeanFactory정의를 찾을 수 없는 빈 인스턴스를 요청합니다.이는 존재하지 않는 빈, 고유하지 않은 빈 또는 관련된 빈 정의가 없는 수동 등록 싱글톤 인스턴스를 가리킬 수 있습니다.

A는 기본적으로 Spring의 Inversion of Control 컨테이너를 나타내는 추상화입니다.그것은 당신의 애플리케이션에 내외부적으로 콩을 노출시킵니다.이 콩들을 찾거나 회수할 수 없을 때, 그것은 던집니다.NoSuchBeanDefinitionException.

아래는 왜 a인지에 대한 간단한 이유입니다.BeanFactory(또는 관련 수업에서) 콩을 찾을 수 없을 것이고 어떻게 콩을 찾을 수 있는지 확인할 수 있을 것입니다.


콩이 존재하지 않습니다. 등록되지 않았습니다.

아래 예제에서

@Configuration
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
        ctx.getBean(Foo.class);
    }
}

class Foo {}   

우리는 유형에 대한 콩 정의를 등록하지 않았습니다.Foo를 통해서 또는@Bean법,@Component스캔, XML 정의, 또는 다른 방법.BeanFactory가 관리하는AnnotationConfigApplicationContext따라서 요청한 콩을 어디서 얻을 것인지에 대한 표시가 없습니다.getBean(Foo.class)을 던집니다. 위의 토막글은 다음과 같이 던집니다.

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
    No qualifying bean of type [com.example.Foo] is defined

마찬가지로, 예외는 다음을 만족시키기 위해 노력하는 동안에 던져질 수 있었습니다.@Autowired의존.예를들면,

@Configuration
@ComponentScan
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
    }
}

@Component
class Foo { @Autowired Bar bar; }
class Bar { }

여기에는 다음에 대한 콩 정의가 등록되어 있습니다.Foo해를 @ComponentScan. 하지만 봄은 아무것도 몰라요Bar. 따라서 자동 배선을 시도하는 동안 해당 빈을 찾지 못합니다.bar야전의Foo콩 예(a 안에 둥지를 틀었습니다)

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

콩 정의를 등록하는 방법은 여러 가지가 있습니다.

  • @Beana의 메소드@Configuration계급이나<bean>ML 구성으로
  • @Component(그리고 메타 annot화 등).@Repository)을 통하여@ComponentScan아니면<context:component-scan ... />
  • 수동으로 통과
  • 수동으로 통과BeanDefinitionRegistryPostProcessor

...그리고 그 이상.

당신이 기대하는 콩이 제대로 등록되었는지 확인하세요.

일반적인 오류는 콩을 여러 번 등록하는 것입니다. 즉, 동일한 종류에 대해 위의 옵션을 혼합하는 것입니다.예를 들면 제가.

@Component
public class Foo {}

를 포함한 XML 구성.

<context:component-scan base-packages="com.example" />
<bean name="eg-different-name" class="com.example.Foo />

그러한 구성은 두 종류의 콩을 등록할 것입니다.Foo, 이름있는 사람foo그리고 또 다른 이름을 가진.eg-different-name보다 더 콩을 것은 실수로 당신이 원하는 것보다 더 많은 콩을 등록하는 것은 아닌지 확인하세요.그래서 우리는...

XML 및 주석 기반 구성을 모두 사용하는 경우 다른 구성에서 하나를 가져오는지 확인합니다.XML이 제공합니다.

<import resource=""/>

자바는 주석을 제공합니다.

일치하는 단일 빈이 필요하지만 2개 이상 발견됨

같은 종류(또는 인터페이스)에 여러 개의 콩이 필요할 때가 있습니다.예를 들어 응용프로그램에서 MySQL 인스턴스와 Oracle 인스턴스의 두 데이터베이스를 사용할 수 있습니다.그런 경우에는 두개의DataSource각각의 연결을 관리하기 위한 콩(간소화) 예를 들어, 다음과 같습니다.

@Configuration
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
        System.out.println(ctx.getBean(DataSource.class));
    }
    @Bean(name = "mysql")
    public DataSource mysql() { return new MySQL(); }
    @Bean(name = "oracle")
    public DataSource oracle() { return new Oracle(); }
}
interface DataSource{}
class MySQL implements DataSource {}
class Oracle implements DataSource {}

던지다

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
    No qualifying bean of type [com.example.DataSource] is defined:
        expected single matching bean but found 2: oracle,mysql

왜냐하면 두 콩이 모두 등록을 했기 때문입니다.@Bean메소드는 다음의 요건을 충족했습니다. 즉, 둘 다 구현합니다.DataSource두 를 지정할 이 예제에서 스프링은 두 가지를 구별하거나 우선 순위를 지정하는 메커니즘이 없습니다.하지만 그러한 메커니즘은 존재합니다.

설명서와 이 게시물에 설명된 대로 (및 XML에 해당)을 사용할 수 있습니다.이 변경으로

@Bean(name = "mysql")
@Primary
public DataSource mysql() { return new MySQL(); } 

이전 토막글은 예외를 던지지 않고 대신 반환합니다.mysql콩을

사용할 수도 있습니다.@Qualifier(및 XML로 동등) 문서에 설명된 대로 빈 선택 프로세스에 대한 더 많은 제어권을 가질 수 있습니다.하는 동안에@Autowired주로 유형별로 자동 배선에 사용됩니다.@Qualifier이름으로 자동 배선할 수 있습니다.예를들면,

@Bean(name = "mysql")
@Qualifier(value = "main")
public DataSource mysql() { return new MySQL(); }

이제는 다음과 같이 주입될 수 있습니다.

@Qualifier("main") // or @Qualifier("mysql"), to use the bean name
private DataSource dataSource;

문제없이@Resource 는 옵션이기도 합니다.

잘못된 콩 이름 사용

콩을 등록하는 방법이 여러 가지가 있듯이 콩 이름을 짓는 방법도 여러 가지가 있습니다.

@Bean 가진.

이 콩의 이름 또는 복수인 경우 이 콩의 별칭입니다.지정되지 않은 상태로 두면 콩의 이름이 주석이 달린 메서드의 이름입니다.지정할 경우 메서드 이름이 무시됩니다.

<bean>가 있습니다.id빈에 대한 고유 식별자를 나타내는 속성과name (XML) ID에서 하나 이상의 별칭을 만드는 데 사용할 수 있습니다.

@Component 그리고 그것의 메타 주석들은

이 값은 논리적 구성 요소 이름을 제안하는 것을 나타낼 수 있으며, 자동으로 감지된 구성 요소의 경우 스프링 빈으로 바꿉니다.

지정되지 않은 상태로 두면 주석이 달린 유형(일반적으로 유형 이름의 하위 낙타 대소문자 버전)에 대한 빈 이름이 자동으로 생성됩니다.예를들면MyClassName된다myClassName이름 그대로콩 이름은 대소문자를 구분합니다.또한 잘못된 이름/자본금은 일반적으로 다음과 같이 문자열로 언급되는 콩에서 발생합니다.@DependsOn("my BeanName")또는 XML 구성 파일을 선택합니다.

@Qualifier, 앞에서 언급했듯이, 콩에 더 많은 별칭을 추가할 수 있습니다.

콩을 지칭할 때는 반드시 올바른 이름을 사용해야 합니다.


보다 발전된 사례

프로필

콩 정의 프로파일을 사용하면 조건부로 콩을 등록할 수 있습니다. , 구체적으로,

하나 이상의 지정된 프로파일이 활성화된 경우 구성요소가 등록 대상임을 나타냅니다.

프로파일은 다음을 통해 프로그래밍적으로 활성화되거나 설정을 통해 선언적으로 활성화될 수 있는 명명된 논리적 그룹입니다.spring.profiles.activeJVM 시스템 속성, 환경 변수 또는 웹 응용 프로그램에 대한 web.xml의 Servlet context 매개 변수로 속성을 지정합니다.프로파일은 주석을 통해 통합 테스트에서 선언적으로 활성화될 수도 있습니다.

예를 들어, 다음과 같은 경우에spring.profiles.active속성이 설정되지 않았습니다.

@Configuration
@ComponentScan
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
        System.out.println(Arrays.toString(ctx.getEnvironment().getActiveProfiles()));
        System.out.println(ctx.getBean(Foo.class));
    }
}

@Profile(value = "StackOverflow")
@Component
class Foo {
}

이렇게 하면 활성 프로파일이 표시되지 않고 다음과 같이 표시됩니다.NoSuchBeanDefinitionException당분간은Foo콩. 그때부터.StackOverflow프로파일이 활성화되지 않았고 콩도 등록되지 않았습니다

대신에 제가 초기화를 하면ApplicationContext해당 프로필을 등록하면서

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("StackOverflow");
ctx.register(Example.class);
ctx.refresh();

콩이 등록되어 있으며 반품/injected 가능합니다.

AOP 프록시

스프링은 고급 동작을 구현하기 위해 AOP 프록시를 많이 사용합니다.다음과 같은 예가 있습니다.

이를 위해 Spring은 두 가지 옵션을 선택할 수 있습니다.

  1. JDK의 Proxy 클래스를 사용하여 실행bean의 인터페이스만 구현하고 모든 메서드 호출을 실제 bean 인스턴스에 위임하는 동적 클래스의 인스턴스를 만듭니다.
  2. CGLIB 프록시를 사용하여 인터페이스와 대상 빈의 구체적인 유형을 모두 구현하고 모든 메서드 호출을 실제 빈 인스턴스에 위임하는 동적 클래스의 인스턴스를 런타임에 생성합니다.

다음 JDK 프록시 예제를 사용합니다.@EnableAsync의 채무 불이행proxyTargetClassfalse)

@Configuration
@EnableAsync
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
        System.out.println(ctx.getBean(HttpClientImpl.class).getClass());
    }
}

interface HttpClient {
    void doGetAsync();
}

@Component
class HttpClientImpl implements HttpClient {
    @Async
    public void doGetAsync() {
        System.out.println(Thread.currentThread());
    }
}

여기서 봄은 유형의 콩을 찾으려고 시도합니다.HttpClientImpl우리가 찾을 것으로 기대하는 것은 그 유형에 명확한 주석이 달렸기 때문입니다.@Component 하지만, 대신에 우리는 예외를 받습니다.

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: 
    No qualifying bean of type [com.example.HttpClientImpl] is defined

봄이 그를 감쌌습니다.HttpClientImpl콩을 통해 그것을 노출시켰습니다.Proxy구현만 하는 대상HttpClient할 수 . 그래서 당신은 그것을 회수할 수 있었습니다.

ctx.getBean(HttpClient.class) // returns a dynamic class: com.example.$Proxy33
// or
@Autowired private HttpClient httpClient;

인터페이스에 프로그래밍하는 것이 항상 권장됩니다.그럴 수 없을 때는 Spring에게 CGLIB 프록시를 사용하라고 하면 됩니다.예를 들어, 을 사용하여 다음과 같이 설정할 수 있습니다.true ()EnableTransactionManagement. ) . XML에도 .XML에는 동등한 구성 옵션도 있습니다.

ApplicationContextIMT2000 3GPP - - 층 -링 MVC

봄은 당신이 건축할 수 있게 해줍니다.ApplicationContext다른 사람들과의 예ApplicationContext부모로서 예를 사용합니다. 자식 컨텍스트는 부모 컨텍스트에서 콩에 대한 액세스 권한을 갖지만, 그 반대는 사실이 아닙니다.이 게시물은 특히 Spring MVC에서 언제 이것이 유용한지에 대해 자세히 설명합니다.

일반적인 Spring MVC 응용 프로그램에서는 전체 응용 프로그램(루트)에 대한 컨텍스트와 특별히 (라우팅, 핸들러 메소드, 컨트롤러)에 대한 컨텍스트 두 가지를 정의합니다.자세한 내용은 여기에서 확인할 수 있습니다.

여기 공식 문서에도 아주 잘 설명되어 있습니다.

Spring MVC 구성의 일반적인 오류는 다음과 같은 루트 컨텍스트에서 WebMVC 구성을 선언하는 것입니다.@EnableWebMvc주석이 달린@Configuration수업이나<mvc:annotation-driven />XML에서, 그러나 서블릿 맥락에서 콩.루트 컨텍스트가 서블릿 컨텍스트에 도달하여 빈을 찾을 수 없으므로 핸들러가 등록되지 않고 모든 요청이 404s로 실패합니다.당신은 볼 수 없을 것입니다.NoSuchBeanDefinitionException, 하지만 효과는 같습니다.

적절한 맥락에서 콩이 등록되었는지 확인합니다. 즉, WebMVC에 등록된 콩으로 찾을 수 있는 곳(HandlerMapping,HandlerAdapter,ViewResolver,ExceptionResolver),).가장 좋은 해결책은 콩을 적절히 격리하는 것입니다.DispatcherServlet모든 관련된 콩들이 그것의 맥락으로 들어가야 하도록 요청을 라우팅하고 처리하는 책임이 있습니다. 더ContextLoaderListener, 루트 컨텍스트를 로드하는 경우 나머지 애플리케이션 요구사항인 서비스, 저장소 등을 초기화해야 합니다.

어레이, 컬렉션 및 맵

일부 알려진 유형의 콩은 봄에 의해 특별한 방식으로 취급됩니다.예를 들어, 다음의 배열을 주입하려고 하면MovieCatalog들판으로

@Autowired
private MovieCatalog[] movieCatalogs;

봄은 모든 종류의 콩을 찾을 것입니다.MovieCatalog, 배열로 감싸고 그 배열을 주입합니다.이것은 다음을 논의하는 Spring 문서에 설명되어 있습니다. 유사한 행동이 적용됩니다.Set,List,그리고.Collection주사 목표물

일단은Map주입 대상, 키 유형이 다음과 같다면 스프링도 이와 같이 동작합니다.String를 들면, 있다면요. 예를 들어, 만약 당신이

@Autowired
private Map<String, MovieCatalog> movies;

봄은 모든 종류의 콩을 찾을 것입니다.MovieCataloga에 값으로 추가합니다.Map, 거기에 해당하는 키가 그들의 콩 이름이 될 것입니다.

앞서 설명한 바와 같이 요청된 유형의 콩이 없다면 스프링은 다음과 같은 작업을 수행할 것입니다.NoSuchBeanDefinitionException과 같은 의 빈(을하고 싶을 때도 하지만 때로는 다음과 같은 컬렉션 유형의 빈을 선언하고 싶을 때도 있습니다.

@Bean
public List<Foo> fooList() {
    return Arrays.asList(new Foo());
}

주사를 놓는 겁니다

@Autowired
private List<Foo> foos;

이 예에서 스프링은 다음과 같이 고장납니다.NoSuchBeanDefinitionException없기 때문에Foo상황에 맞는 콩.하지만 당신은 원하지 않았잖나Foo콩, 당신은 원하셨잖아요.List<Foo>콩. 봄 4.3 이전에는.

자체적으로 집합/지도 또는 배열형으로 정의된 콩의 경우,@Resource는 특정 컬렉션 또는 배열 빈을 고유한 이름으로 지칭하는 미세 솔루션입니다.즉, 4.3 현재 수집/맵 및 배열 유형은 Spring's를 통해 일치시킬 수 있습니다.@Autowired요소 유형 정보가 보존되는 한 유형 일치 알고리즘도 마찬가지입니다.@Bean반환 형식 서명 또는 수집 상속 계층 구조입니다.이 경우 한정자 값을 사용하여 앞 단락에서 설명한 대로 동일한 유형의 집합 중에서 선택할 수 있습니다.

이것은 컨스트럭터, 세터, 필드 인젝션에 적합합니다.

@Resource
private List<Foo> foos;
// or since 4.3
public Example(@Autowired List<Foo> foos) {}

하지만, 그것은 실패할 것입니다.@Bean 즉법,법

@Bean
public Bar other(List<Foo> foos) {
    new Bar(foos);
}

여기서 봄은 어떤 것도 무시합니다.@Resource아니면@Autowired방법에 주석을 다는 것, 왜냐하면 그것은@Beanmethod, 따라서 문서에 설명된 동작을 적용할 수 없습니다.하지만 여러분은 봄의 표현 언어(SpEL)를 사용하여 콩의 이름을 부를 수 있습니다.위의 예에서, 당신은 다음을 사용할 수 있습니다.

@Bean
public Bar other(@Value("#{fooList}") List<Foo> foos) {
    new Bar(foos);
}

이름이 붙은 콩을 가리키다fooList주사를 놔주세요.

언급URL : https://stackoverflow.com/questions/39173982/what-is-a-nosuchbeandefinitionexception-and-how-do-i-fix-it

반응형