来自 YML 的 ConfigurationProperties 加载列表

Posted

技术标签:

【中文标题】来自 YML 的 ConfigurationProperties 加载列表【英文标题】:ConfigurationProperties loading list from YML 【发布时间】:2018-02-03 10:48:47 【问题描述】:

我正在尝试从 YML 加载配置。我可以加载值,如果这些是逗号分隔值,我也可以加载列表。但我无法加载典型的 YML 列表。

配置类

@Component
@PropertySource("classpath:routing.yml")
@ConfigurationProperties
class RoutingProperties()
    var angular = listOf("nothing")
    var value: String = ""

工作路由.yml

angular: /init, /home
value: Hello World

不工作 routing.yml

angular:
    - init
    - home

value: Hello World

为什么我不能加载 yml 的第二个版本/我有语法错误吗?

环境:Kotlin,Spring 2.0.0.M3

【问题讨论】:

在这里看看这个答案:https://***.com/questions/21271468/spring-propertysource-using-yaml/54247009#54247009 .它很容易使用。 【参考方案1】:

有点老帖子,我知道。但我现在正处于同一个话题。

截至目前,PropertySource 似乎确实适用于 yaml 文件。鉴于它只允许原始类型(似乎)并且它不能处理嵌套元素的限制。我可能会更深入地挖掘并相应地更新我的答案,但截至目前,接受的答案似乎是一种有效的解决方法。

【讨论】:

【参考方案2】:

正如@flyx 所说,@PropetySource 不适用于 yaml 文件。但是在春天你可能会覆盖几乎所有东西:)

PropertySource 有附加参数:工厂。可以基于 DefaultPropertySourceFactory 创建自己的 PropertySourceFactory

open class YamlPropertyLoaderFactory : DefaultPropertySourceFactory() 
    override fun createPropertySource(name: String?, resource: EncodedResource?): org.springframework.core.env.PropertySource<*> 
        if (resource == null)
            return super.createPropertySource(name, resource)

        return YamlPropertySourceLoader().load(resource.resource.filename, resource.resource, null)
    

当在propertysource注解中使用这个工厂时:

@PropertySource("classpath:/routing.yml", factory = YamlPropertyLoaderFactory::class)

最后你需要用 mutableList 初始化变量 angular

完整代码示例:

@Component
@PropertySource("classpath:/routing.yml", factory = YamlPropertyLoaderFactory::class)
@ConfigurationProperties
open class RoutingProperties 
    var angular = mutableListOf("nothing")
    var value: String = ""


    override fun toString(): String 
        return "RoutingProperties(angular=$angular, value='$value')"
    


open class YamlPropertyLoaderFactory : DefaultPropertySourceFactory() 
    override fun createPropertySource(name: String?, resource: EncodedResource?): org.springframework.core.env.PropertySource<*> 
        if (resource == null)
            return super.createPropertySource(name, resource)

        return YamlPropertySourceLoader().load(resource.resource.filename, resource.resource, null)
    


@SpringBootApplication
@EnableAutoConfiguration(exclude = arrayOf(DataSourceAutoConfiguration::class))
open class Application 
    companion object 
        @JvmStatic
        fun main(args: Array<String>) 
            val context = SpringApplication.run(Application::class.java, *args)

            val bean = context.getBean(RoutingProperties::class.java)

            println(bean)
        
    
 

【讨论】:

如果需要获取特定配置文件的属性,YamlPropertySourceLoader.load() 中的第三个参数是配置文件名称。虽然,YamlPropertySourceLoader.load() 已更改为返回一个列表而不是单个属性源,因此您需要在列表中找到与您的配置文件匹配的那个。这里有更多信息***.com/a/53697551/10668441 根据问题 spring 版本是 2.0.0 在@PropertySource 中没有这个工厂选项【参考方案3】:

嗯,根据the docs,你的YAML文件会被重写成一个属性文件。第一个 YAML 文件变为:

angular=/init, /home
value=Hello World

而第二个变成:

angular[0]=init
angular[1]=home
value=Hello World

这显然是两个非常不同的东西,因此表现也不同。

此外,在文档的后面,据说 YAML 甚至不适用于 @PropertySource

24.6.4 YAML 缺点

YAML 文件不能通过@PropertySource 注解加载。因此,如果您需要以这种方式加载值,则需要使用属性文件。

这让我有点想知道为什么第一个案例完全适合你。

文档对生成的…[index] 属性这么说:

要使用 Spring DataBinder 实用程序(这是 @ConfigurationProperties 所做的)绑定到类似的属性,您需要在目标 bean 类型为 java.util.List(或 Set)中拥有一个属性,并且您需要提供一个设置器,或者用一个可变值初始化它,例如这将绑定到上面的属性

那么,让我们看看 Kotlin 文档:listOf 返回给定元素的新只读列表。因此,该列表按照文档的要求不可变,我认为这就是它不起作用的原因。尝试使用可变列表(因为我从未使用过 Kotlin,所以我不能给你工作代码)。如果在 Kotlin 中可行,也尝试将其声明为 java.util.List

【讨论】:

我无法解释原因,但我能够使用 PropertySource 加载 YAML。最新的春季版本可能会发生变化。因为我能够加载字符串但没有列表。无论如何,我也尝试过 mutableList 但它没有用。但是使用不可变列表 YAML 列表逗号分隔 (/init, /home) 有效

以上是关于来自 YML 的 ConfigurationProperties 加载列表的主要内容,如果未能解决你的问题,请参考以下文章

当您尝试对其运行 JUnit 测试时,不会为独立应用程序加载来自“application.yml”的属性

Spring boot 2.4.x 无法处理来自配置服务器的多文档 yml 文件

包含来自snakeyaml 的YAML 文件

如何在 ruby​​ 中使用来自 yaml 的登录凭据

yml和properties

Anaconda:使用environment.yml从特定通道安装特定包