DI将String bean注入为List <string>的单个元素,而不是适当的List <string> bean

时间:2019-04-29 18:01:20

标签: java spring spring-boot spring-4

我是第一次学习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批注,它只是无法启动。

2 个答案:

答案 0 :(得分:2)

默认情况下,@Autowired将尝试按类型查找bean。在您的BookBean类中,您将注入String titleList<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)。在您的情况下,这是titleA 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;
}