我是第一次学习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。 / p>
反过来,这使我相信我可能会以错误的方式进行整个Autowired事情,并且可能无法按要求按类型/名称排列自动布线。据我了解,默认的自动装配是按Type进行的,并且构造函数应尝试查找两种不同类型的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的标题为:“示例书”,作者为:[“示例书”],当作者的实际值应为:[“ John”,“ Adam”,“哈里”]
使用@Qualifier批注,它只是无法启动。
答案 0 :(得分:2)
默认情况下,@Autowired
将尝试按类型查找bean。在您的BookBean
类中,您将注入String title
和List<String> authors
。
Spring在引擎盖下做什么?
字符串标题-将在其中找到一个 String类型的Bean(如果找到多个,则需要一个@Qualifier来确定要注入哪个)。您的案子@Bean String title()
列出作者-它会尝试查找所有类型为String的Bean,在您的方案中,您只有一个:title()
最后,除非您使用List<String> authors()
进行注入,否则将无法访问您的@Resource(id ="authors")
bean。
回溯几步,您永远不要依赖原语进行依赖项注入,因为它们可能会误导您。我建议将它们包装在某些类中,也可以定义一个Title
类和一个Authors
类如果,您确实需要使用依赖注入。
答案 1 :(得分:1)
当在类型化的集合或数组上出现@Bean批注时,该bean将自动被应用程序上下文注册的该类型的所有bean填充(请参见reference documentation)。在您的情况下,这是title
(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;
}