1. 概要

このチュートリアルでは、Springorg.springframework.beans.factory.NoSuchBeanDefinitionException。について説明します。

これは、Springコンテキストでが定義されていない a beanを解決しようとしたときに、 BeanFactoryによってスローされる一般的な例外です。

この問題の考えられる原因と利用可能な解決策を説明します。

そしてもちろん、例外は私たちが最も期待しないときに発生するので、Springの例外と解決策の完全なリストを見てください。

2. 原因:依存関係に対応するタイプの適格なBeanが見つかりません[…]

この例外の最も一般的な原因は、定義されていないbeanを挿入しようとしていることです。

たとえば、 BeanB は、コラボレーターBeanAで配線しています。

@Component
public class BeanA {

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

これで、依存関係 BeanBがSpringContextで定義されていない場合、ブートストラッププロセスはそのようなBean定義の例外なしで失敗します。

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によって明確に示されています。この依存関係のautowire候補として適格な少なくとも1つのBeanが必要です

BeanB がコンテキストに存在しない理由の1つ— クラスパススキャンによってBeanが自動的に取得され、 BeanB がBeanとして正しく注釈付けされている場合([X182X ] @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が必要でしたが見つかりませんでした

上記のシナリオのSpringBootアプリケーションでは、別のメッセージが表示されます。

BeanBBeanAに配線されているが、定義されていない同じ例を見てみましょう。

@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.nosuchbeandefinitionexception は、 BeanA BeanB 、およびNoSuchBeanDefinitionDemoAppのパッケージです。

この例のスニペットは、このGitHubプロジェクトにあります。

4. 原因:タイプ[…]の修飾Beanが定義されていません

例外のもう1つの原因は、コンテキスト内に1つではなく2つのBean定義が存在することです。

インターフェイスIBeanBが2つのBeanBeanB1BeanB2によって実装されているとします。

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

BeanA がこのインターフェースを自動配線する場合、Springは2つの実装のどちらを注入するかを認識しません。

@Component
public class BeanA {

    @Autowired
    private IBeanB dependency;
    ...
}

また、これにより、[X32X]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です。この新しい例外はSpring3.2.1で導入されました。まさにこの理由のために— Bean定義が見つからなかった原因と、コンテキスト内でいくつかの定義が見つかった原因を区別するため。

この変更前は、これは上記の例外でした。

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

この問題の解決策の1つは、@ Qualifierアノテーションを使用して、ワイヤリングするBeanの名前を正確に指定することです。

@Component
public class BeanA {

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

これで、Springには、注入するBeanを決定するのに十分な情報があります— BeanB1またはBeanB2BeanB2のデフォルト名はbeanB2 )。

5. 原因:名前の付いたBeanがありません[…]が定義されています

NoSuch Bean DefinitionException は、定義されていないbeanがSpringコンテキストから名前によって要求された場合にもスローされる可能性があります。

@Component
public class BeanA implements InitializingBean {

    @Autowired
    private ApplicationContext context;

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

この場合、「someBeanName」のBean定義がないため、次の例外が発生します。

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

繰り返しになりますが、Springは失敗の理由を明確かつ簡潔に示しています。Xという名前のBeanは定義されていません

6. 原因:プロキシされたBean

コンテキスト内のBeanがJDKDynamicProxyメカニズムを使用してプロキシされる場合、プロキシはターゲットBean を拡張しません(ただし、同じインターフェースを実装します)。

このため、Beanがインターフェースによって注入された場合、Beanは正しく配線されます。 ただし、Beanが実際のクラスによって注入された場合、プロキシは実際にはクラスを拡張しないため、Springはクラスに一致するBean定義を検出しません。

Beanがプロキシされる非常に一般的な理由は、 Springトランザクションサポート、つまり@Transactionalで注釈が付けられたBeanです。

たとえば、ServiceAServiceBを注入し、両方のサービスがトランザクションである場合、クラス定義による注入は機能しません。

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private ServiceB serviceB;
    ...
}

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

同じ2つのサービス、今回は正しくインターフェイスによる注入で問題ありません。

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private IServiceB serviceB;
    ...
}

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

7. 結論

この記事では、一般的な NoSuchBeanDefinitionException の考えられる原因の例について、実際にこれらの例外に対処する方法に焦点を当てて説明しました。

これらすべての例外の例の実装は、GitHubプロジェクトにあります。 これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。

最後に、Springの例外と解決策の完全なリストは、ブックマークするのに適したリソースになる可能性があります。