【发布时间】:2019-09-18 09:17:33
【问题描述】:
我是第一次学习 Spring Framework 和 DI,并尝试了一个带有 Spring-boot 1.2.0 的小测试应用程序(由于 Spring Framework 版本要求为 4.1.x,项目限制),我制作了一个 BookBean,它有两个属性:一个字符串标题和一个作者列表。显然 DI 将标题作为列表的唯一成员注入,我完全不知道为什么。
我在标记为 @Bean 的方法上添加了一些日志记录,以查看它们何时被调用以及 BookBean 构造函数,我注意到在调用构造函数之后调用了 String 方法:
[2019-04-29 14:46:05.631] boot - 3888 INFO [main] --- CollectionConfig: returning title: [A sample book]
[2019-04-29 14:46:05.637] boot - 3888 INFO [main] --- BookBean: construction called
[2019-04-29 14:46:05.649] boot - 3888 INFO [main] --- CollectionConfig: returning authors: [[John, Adam, Harry]]
这让我相信 DI 在尝试构造 BookBean 时没有可用的 List bean,并且“做了次好的事情”,返回一个注入了它知道的唯一 String bean 的 List:title。
反过来,这让我相信我可能以错误的方式做整个 Autowired 事情,并且我可能无法按照要求按类型/名称排列自动装配。据我了解,默认自动装配是按类型,构造函数应该尝试查找两种不同类型的 bean:String 和 List,但我尝试使用 @Bean(name = "title"/"authors" 注释 bean ) 没有成功。如果我还尝试使用 @Qualifier("title"/"authors") 注释构造函数参数,则会收到以下错误:
[2019-04-29 14:54:25.847] boot - 20824 INFO [main] --- CollectionConfig: returning title: [A sample book]
[2019-04-29 14:54:25.853] boot - 20824 WARN [main] --- AnnotationConfigEmbeddedWebApplicationContext: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookBean' defined in URL [jar:file:/C:/dev/Repos/branches/branch_rest_remake/branch_2019_04_11/webapp/target/webapp-0.0.1-SNAPSHOT.jar!/com/company/spring/webapp/domain/BookBean.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [java.util.List]: : No qualifying bean of type [java.lang.String] found for dependency [collection of java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=authors)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency [collection of java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=authors)}
这些是我的类:(编辑 - 从示例中删除了 Logger 实例,但它们在代码中)
@RestController
@RequestMapping("/")
public class DummyController {
@Autowired
private BookBean bookBean;
@RequestMapping("/di")
String dummyDependencyInjection() {
logger.info("called /di");
return bookBean.printAuthors();
}
}
@Configuration
public class CollectionConfig {
@Bean
public String title() {
String title = "A sample book";
logger.info("returning title: ["+title+"]");
return title;
}
@Bean
public List<String> authors() {
List<String> authors = Arrays.asList("John", "Adam", "Harry");
logger.info("returning authors: ["+authors+"]");
return authors;
}
}
@Component
public class BookBean {
private String title;
private List<String> authors;
@Autowired
public BookBean(String title, List<String> authors) {
logger.info("construction called");
this.title = title;
this.authors = authors;
}
public String printAuthors() {
logger.info("printAuthors called");
return "Authors in "+ title + "\n"+authors;
}
}
如果没有 @Qualifier 注释,bean 将使用标题:“A sample book”和 authors:[“A sample book”] 而作者的实际值应该是:[“John”,“Adam”,“哈利”]
使用@Qualifier 注解,它只是无法启动。
【问题讨论】:
-
问题是你可以从同一个对象创建多个bean,所以你可以使用
@Autowire List<MyObject> objs来获取这个类型的所有bean作为列表。对于每个@Bean一个带有方法名称的 bean(如果您没有自己指定),因此如果您有多个相同类型的 bean,则如果您想访问单个 bean,则必须使用该名称。 -
@SamuelPhilipp 确实,我尝试添加第二个 String bean,并且 DI 同时返回“A sample title”和数组上的新 bean,我不知道默认情况下列表是如何工作的。我读到使用限定符应该可以工作,但到目前为止我一直在逃避。
标签: java spring spring-boot spring-4