Java 使用Spring,如何将子bean注入父bean?
我有一个Bean想要注入它的子类,如下所示: 家长:Java 使用Spring,如何将子bean注入父bean?,java,spring,Java,Spring,我有一个Bean想要注入它的子类,如下所示: 家长: package test; @Component public class Parent { @Autowired Child child; public Child getChild() { return child; } } 儿童: package test; @Component public class Child extends Parent { } 这将导致以下错误: org.springfram
package test;
@Component
public class Parent {
@Autowired
Child child;
public Child getChild() {
return child;
}
}
儿童:
package test;
@Component
public class Child extends Parent {
}
这将导致以下错误:
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
删除extensedparent
位会使一切按预期工作,因此Spring似乎无法找到子级,就好像父级以某种方式对其进行了跟踪。如何配置Spring以正确连接这些子实例?我正在使用Java类配置,如下所示:
@Configuration
@ComponentScan(basePackages = "test")
public class AppConfig {
}
我尝试过使用@Qualifier
注释,并在AppConfig
中指定不同的名称,如下所示,但没有任何帮助:
@Bean(name = "parent")
public Parent parent() {
return new Parent();
}
@Bean(name = "child")
public Child child() {
return new Child();
}
为了让Spring将子类视为自己独特的实体,我不确定缺少什么成分。这是不可能的吗?因为
子扩展了父,必须构造父来构造子,但是父需要子来构造。这是一个循环依赖;避免在代码中创建循环依赖项
您需要重构代码。这在您的代码库中可能不可能实现,但如果您可以反转关系,以便父级
扩展子级
(而不是现在的反向),您将能够注入:
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 {
}
或者,将子级
和父级
都需要的代码重构到另一个类中,并将该代码注入父级
和子级
:
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 {
}
由于子项
扩展了父项
,因此必须构造父项
来构造子项
,但是父项
需要一个子项
来构造。这是一个循环依赖;避免在代码中创建循环依赖项
您需要重构代码。这在您的代码库中可能不可能实现,但如果您可以反转关系,以便父级
扩展子级
(而不是现在的反向),您将能够注入:
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 {
}
或者,将子级
和父级
都需要的代码重构到另一个类中,并将该代码注入父级
和子级
:
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 {
}
我通过修改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 {
}
并对子对象进行如下修改:
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。我通过修改父定义解决了这个问题,如下所示:
package test;
@Primary
@Component
public class Parent {
@Resource
Child child;
public Child getChild() {
return child;
}
}
package test;
@Component("child")
public class Child extends 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。请原谅,但我不理解您的代码片段中真正解决问题的部分。我看到您删除了Child上的@组件
注释,但对我的组件做同样的操作不会改变任何东西。您还创建了一个新类,并在我的问题中省略了一个类,我不清楚这会如何改变解决方案。我错过了子
上的扩展父
-这会创建循环依赖关系,这就是您看到此问题的原因。我会更新我的答案。看起来我也忽略了这个遗漏。我不认为循环依赖是这个问题的原因。我可以轻松创建两个相互自动连接的类,而不会出现问题,我发现通过将@Autowired
注释更改为@Resource
,可以避免此错误。这意味着问题与类型查找本身有关,不是吗?请原谅,但我不理解代码片段中真正解决问题的部分。我看到您删除了Child上的@组件
注释,但对我的组件做同样的操作不会改变任何东西。您还创建了一个新类,并在我的问题中省略了一个类,我不清楚这会如何改变解决方案。我错过了子
上的扩展父
-这会创建循环依赖关系,这就是您看到此问题的原因。我会更新我的答案。看起来我也忽略了这个遗漏。我不认为循环依赖是这个问题的原因。我可以轻松创建两个相互自动连接的类,而不会出现问题,我发现通过将@Autowired
注释更改为@Resource
,可以避免此错误。这意味着问题与类型查找本身有关,不是吗?这对我来说失败了,@user108471,初始错误;我正在使用Spring Boot 1.3.3&JDK 8,它在Linux上使用Spring 4.2.5。@JanNielsen抱歉,看起来我遗漏了另一个重要的更改:向子类添加显式名称。这对我来说失败,@user108471,初始错误;我使用的是Spring Boot 1.3.3&JDK 8,它在Linux上使用Spring 4.2.5。@JanNielsen抱歉,看起来我遗漏了另一个重要的更改:为子类添加显式名称。