DI 将 String bean 作为 List<String> 的单个元素而不是正确的 List<String> bean 注入
DI injecting a String bean as single element of a List<String> instead of the proper List<String> bean
我是第一次学习 Spring 框架和 DI,并尝试使用 Spring-boot 1.2.0 的小测试应用程序(由于 Spring 框架版本要求的项目限制be 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,并且 "does the next best thing" 返回一个注入了它知道的唯一 String bean 的 List:title。
反过来,这让我相信我可能以错误的方式进行了整个自动装配,并且我可能无法按要求按 type/name 排列自动装配。据我了解,默认的自动装配是按类型进行的,构造函数应该尝试寻找两种不同类型的 bean:String 和 List,但我尝试用 @Bean(name = "title"/"authors") 没有成功。如果我还尝试使用 @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" 和作者:["A sample book"] 构建,而作者的实际值应为:["John","Adam", "Harry"]
使用@Qualifier 注释,它只是无法启动。
当类型化集合或数组上出现 @Bean 批注时,该 bean 将自动填充应用程序上下文注册的该类型的所有 bean(请参阅 reference documentation)。在您的情况下,这是 title
been (A sample book
),因此 authors
列表仅包含该条目。
如果您想自动装配特定的 bean,您可以使用 @Qualifier
注释(参见 reference documentation)来引用该名称。
在你的情况下,构造函数可以重写为:
@Autowired
public BookBean(String title, @Qualifier("authors") List<String> authors) {
this.title = title;
this.authors = authors;
}
使用类型化集合时 reference documentation actually suggests(在灰色部分下方稍微向下滚动)。您要使用@Resource 注释:
private String title;
@Resource
private List<String> authors;
public BookBean(String title) {
this.title = title;
}
默认情况下 @Autowired
将尝试按类型查找 beans。在您的 BookBean
class 中,您正在注入一个 String title
和一个 List<String> authors
.
Spring 是做什么的?
String title - 它会找到 a String 类型的 Bean(如果找到多个,它需要一个 @Qualifier 来确定注入哪一个),在你的情况下 @Bean String title()
List authors - 它将尝试查找 all String 类型的 Beans,在您的场景中您只有一个:title()
总而言之,您的 List<String> authors()
bean 将无法访问,除非您使用 @Resource(id ="authors")
注入它。
退后几步,您永远不应该依赖原语进行依赖注入,因为它们可能会误导您。我建议将它们包装在一些 classes 中,a.k.a 定义一个 Title
class 和一个 Authors
class if 你真的需要使用依赖注入。
我是第一次学习 Spring 框架和 DI,并尝试使用 Spring-boot 1.2.0 的小测试应用程序(由于 Spring 框架版本要求的项目限制be 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,并且 "does the next best thing" 返回一个注入了它知道的唯一 String bean 的 List:title。
反过来,这让我相信我可能以错误的方式进行了整个自动装配,并且我可能无法按要求按 type/name 排列自动装配。据我了解,默认的自动装配是按类型进行的,构造函数应该尝试寻找两种不同类型的 bean:String 和 List,但我尝试用 @Bean(name = "title"/"authors") 没有成功。如果我还尝试使用 @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" 和作者:["A sample book"] 构建,而作者的实际值应为:["John","Adam", "Harry"]
使用@Qualifier 注释,它只是无法启动。
当类型化集合或数组上出现 @Bean 批注时,该 bean 将自动填充应用程序上下文注册的该类型的所有 bean(请参阅 reference documentation)。在您的情况下,这是 title
been (A sample book
),因此 authors
列表仅包含该条目。
如果您想自动装配特定的 bean,您可以使用 @Qualifier
注释(参见 reference documentation)来引用该名称。
在你的情况下,构造函数可以重写为:
@Autowired
public BookBean(String title, @Qualifier("authors") List<String> authors) {
this.title = title;
this.authors = authors;
}
使用类型化集合时 reference documentation actually suggests(在灰色部分下方稍微向下滚动)。您要使用@Resource 注释:
private String title;
@Resource
private List<String> authors;
public BookBean(String title) {
this.title = title;
}
默认情况下 @Autowired
将尝试按类型查找 beans。在您的 BookBean
class 中,您正在注入一个 String title
和一个 List<String> authors
.
Spring 是做什么的?
String title - 它会找到 a String 类型的 Bean(如果找到多个,它需要一个 @Qualifier 来确定注入哪一个),在你的情况下 @Bean String title()
List authors - 它将尝试查找 all String 类型的 Beans,在您的场景中您只有一个:title()
总而言之,您的 List<String> authors()
bean 将无法访问,除非您使用 @Resource(id ="authors")
注入它。
退后几步,您永远不应该依赖原语进行依赖注入,因为它们可能会误导您。我建议将它们包装在一些 classes 中,a.k.a 定义一个 Title
class 和一个 Authors
class if 你真的需要使用依赖注入。