【发布时间】:2020-12-08 16:10:11
【问题描述】:
我有一个非常简单的 Spring Boot 测试应用程序。
它只有一个 Dog 类和 @SpringBootApplication 注解的类。 我创建了两个 Dog bean,一切都按预期运行。
public class Dog {
public String name;
public Dog() {
this("noname");
}
public Dog(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
@SpringBootApplication
public class DemoApplication {
@Autowired
private List<Dog> dogs;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
CommandLineRunner runner1() {
return args -> {
for (Dog d : dogs) {
System.out.println(d);
}
};
}
@Bean
Dog laika() {
return new Dog("laika");
}
@Bean
Dog lassie() {
return new Dog("lassie");
}
}
输出:
laika
lassie
但是现在我向 Dog 类添加了一个 @Component 注释,期望现在我将得到三个 Dog 类型的 bean,如果我用另一个像这样的 CommandLineRunner 打印所有 bean,这似乎会发生:
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
输出:
Let's inspect the beans provided by Spring Boot:
applicationAvailability
applicationTaskExecutor
commandLineRunner
demoApplication
dog
laika
lassie
lifecycleProcessor
...
然而,当我使用我的第一个 CommandLineRunner 打印出我的 Dog 列表的内容时,我得到的唯一输出是:
noname
似乎@Component bean 使 @Bean 声明的 bean 消失以进行集合注入。我观察到任何 bean 的相同行为,例如,如果我在独立的 @Component 类中声明更多 CommandLineRunners,每个人都会运行,但是当我在列表中 @Autowire 时,只有用 @Component 声明的那些被注入。
不过,我仍然可以使用其他 Dog bean。例如,如果我用 @Primary 注释 Laika bean,它将作为方法参数注入,但 @Autowire 的集合没有任何变化。
【问题讨论】:
-
这是一个奇怪的边缘情况,IMO 不值得深入研究,但这说明了为什么在
@Configuration类中注入 bean 列表可能是一个坏主意(这也负责他们的初始化)。相反,如果你真的想要Dogbean 的列表,请在runner1@Bean方法中指定List<Dog>参数,Spring 将负责将它们全部注入。 -
如果您真的很感兴趣,请在here 中放置一个断点。这就是差异发生的地方。本质上,当
dogs被填充时,Spring 将只考虑在@Configuration类(链接中的isSelfReference)之外声明的bean,但前提是有。如果没有,它也会使用@Bean方法。
标签: java spring spring-boot autowired