org.springframework.beans.factory.NoSuchBeanDefinitionException が出たときの対処
TL;DR
どういうときに起こるかというと、端的に言えばコンポーネントを注入しているけれども、コンポーネントがDIコンテナに存在しない/参照できていない場合に発生します。具体的な例を見てみます。
具体例1:DIコンテナに注入できていない場合
パッケージ構成は以下のようになっているとします。
└─src └─main ├─java │ └─sample │ Hoge.java │ Main.java │ └─resources └─spring applicationContext.xml
spring/applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- <bean id="hoge" class="sample.Hoge"> <constructor-arg value="defaultName" /> </bean> --> </beans>
sample.Main.java
package sample; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Main { public static void main(String[] args) { String[] xmlConfig = new String[] { "classpath:/spring/applicationContext.xml" }; ApplicationContext context = new FileSystemXmlApplicationContext(xmlConfig); Hoge hoge = (Hoge) context.getBean("hoge"); hoge.say(); } }
package sample; public class Hoge { String name; public Hoge(String name) { this.name = name; } void say() { System.out.println(this.name); } }
あえて applicationContext.xml
のbean定義をコメントアウトして実行すると以下のようになります。要は hoge の名前のbeanがないよ、ということです。
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hoge' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:775) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105) at sample.Main.main(Main.java:12)
ということで applicationContext.xml
のコメントアウトを外すと以下のように <constructor-arg value="defaultName" />
で注入している値が取得できます。
defaultName
具体例2:@AutowiredしているcomponentがDIコンテナに注入されていない場合
別の例を見てみます。以下のような構成になっているとします。 DummyDao.java を追加しています。疑似的にDBアクセスするようなパッケージを構成していたとします。(今回の場合はStringの文字列を返却するだけです)
└─src └─main ├─java │ └─sample │ │ Hoge.java │ │ Main.java │ │ │ └─dao │ DummyDao.java │ └─resources └─spring applicationContext.xml
package sample; import org.springframework.beans.factory.annotation.Autowired; import sample.dao.DummyDao; public class Hoge { String name; @Autowired DummyDao dummyDao; public Hoge(String name) { this.name = name; } void say() { System.out.println(dummyDao.find()); } }
DummyDao.java
package sample.dao; import org.springframework.stereotype.Repository; @Repository public class DummyDao { public String find() { return "something"; } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="sample.dao.*" /> <bean id="hoge" class="sample.Hoge"> <constructor-arg value="defaultName" /> </bean> </beans>
上記は <context:component-scan base-package="sample.dao.*" />
としているので実質 DummyDao.java をscanできていません。
よって実行すると以下のような例外 org.springframework.beans.factory.UnsatisfiedDependencyException
が発生します。Hoge.java で @Autowired
しているクラスがDIコンテナから取得できないためです。
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hoge': Unsatisfied dependency expressed through field 'dummyDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'sample.dao.DummyDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} [土 4 20 19:38:08 JST 2019] Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hoge': Unsatisfied dependency expressed through field 'dummyDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'sample.dao.DummyDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1395) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:142) at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:95) at sample.Main.main(Main.java:13) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'sample.dao.DummyDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1654) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1213) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ... 15 more
これは applicationContext.xml の <context:component-scan base-package="sample.dao.*" />
を <context:component-scan base-package="sample.dao" />
とすれば @Repository
を付与している DummyDao.java をDIコンテナから取得できるようになるので実行できます。
something
参考
- java - Spring,Beanの取得について - スタック・オーバーフロー
- java – SpringはすべてのBeanにデフォルトコンストラクタを持たせる必要がありますか? - コードログ 引数なしのデフォルトコンストラクタを作りたくない時
- 2.ApplicationContext.xmlファイルの記述方法 - soracane 一般的な話(versionは古そう)