I have a Bean that wants to inject its child classes like so:
Parent:
package test;
@Component
public class Parent {
@Autowired
Child child;
public Child getChild() {
return child;
}
}
Child:
package test;
@Component
public class Child extends Parent {
}
This results in the following error:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [test.Child] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency
Removing the extends Parent
bit causes everything to work as expected, so it looks like Spring is unable to find the Child, as though the Parent is shadowing it somehow. How do I configure Spring to correctly wire these child instances? I'm using Java Class Configuration, like the following:
@Configuration
@ComponentScan(basePackages = "test")
public class AppConfig {
}
I have tried playing around with the @Qualifier
annotation and assigning distinct names within AppConfig
as in the following, which did not help:
@Bean(name = "parent")
public Parent parent() {
return new Parent();
}
@Bean(name = "child")
public Child child() {
return new Child();
}
I'm not sure what the missing ingredient is in order to make Spring see the Child class as its own distinct entity. Is this not possible?
答案 0 :(得分:2)
我通过修改Parent的定义解决了这个问题,如下所示:
package test;
@Primary
@Component
public class Parent {
@Resource
Child child;
public Child getChild() {
return child;
}
}
并修改孩子如下:
package test;
@Component("child")
public class Child extends Parent {
}
我已将@Autowired
注释替换为@Resource
,它在类型之前尝试按名称查找,并为子类添加了显式名称。为了在尝试自动装配父级时消除孩子的父母歧义,我还将@Primary
注释添加到父级。
我仍然不完全理解为什么按类型查找失败,迫使我使用@Resource
来代替查找bean。
答案 1 :(得分:0)
Since Child
extends Parent
, a Parent
must be constructed to construct a Child
but a Parent
requires a Child
for construction. This is a circular dependency; avoid creating circular dependencies in your code.
You will need to refactor your code. This may not be possible in your code-base, but if you can invert the relationship so Parent
extends Child
(instead of the reverse as you have it now), you'll be able to inject:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private Parent parent;
@Bean
Child makeChild() { return new Child(); }
}
@Component
class Parent extends Child {
@Autowired
private Child child;
public Child getChild() { return this.child; }
}
class Child {
}
Alternatively, refactor the code that both Child
and Parent
need into another class and inject that code into the Parent
and Child
:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private Parent parent;
@Bean
Child makeChild() { return new Child(); }
@Bean
Shared makeShared() { return new Shared(); }
}
@Component
class Parent {
@Autowired
private Shared shared;
@Autowired
private Child child;
public Child getChild() { return this.child; }
}
class Child {
@Autowired
private Shared shared;
}
class Shared {
}