DI将String bean注入List的单个元素 而不是正确的列表 豆

问题描述 投票:0回答:2

我是第一次学习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的东西,并且我可能无法按照要求按类型/名称排列自动装配。我的理解是默认的autowire是Type,并且构造函数应该尝试查找两种不同类型的bean:String和List,但我尝试使用@Bean注释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的标题是:“样本书”和作者:[“样本书”]当作者的实际值应为:[“John”,“Adam”,“Harry”]

使用@Qualifier注释,它无法启动。

java spring spring-boot spring-4
2个回答
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将无法访问。

退后几步,你不应该依赖原语进行依赖注入,因为它们可能会误导你。我建议将它们包装在某些类中,如果你真的需要使用依赖注入,a.k.a定义一个Title类和一个Authors类。


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;
}
© www.soinside.com 2019 - 2024. All rights reserved.