如果一个属性在多个属性文件中定义,Spring如何挑选要使用的属性值?

j9per5c4  于 2022-12-28  发布在  Spring
关注(0)|答案(3)|浏览(119)

如果一个属性在多个属性文件中定义,Spring如何决定变量的值?

□ □ □我猜
基于运行一些代码,我认为结果是不确定的,如果多个属性文件定义了相同的属性名,那么使用哪个属性文件似乎是随机的。

Spring如何实现这一点(我的猜测)

Spring保存了一个PropertySources列表,当需要属性值时,它会逐个遍历PropertySources,直到找到属性值。
这是基于我所做的一些测试和以下答案:来自https://stackoverflow.com/a/74934269/3281336,其内容为:
如果你想得到一个属性,MutablePropertySources的get方法会被调用,它会遍历所有的PropertySources直到找到那个属性。
由于默认情况下,您不知道列表的顺序,因此,您不知道将获得什么值(当一个属性在多个属性文件中定义时)。

我如何向自己证明

为了证明这是如何工作的,我创建了两个属性文件并定义了相同的属性名foo.baz

// File: src/main/resources/file1.properties
foo.baz=Defined in file1.properties

// File: src/main/resources/file2.properties
foo.baz=Defined in file2.properties

接下来,我创建了一个@ConfigurationMyConfig,它读取两个属性文件file1.propertiesfile2.properties

@PropertySource("classpath:datasource.properties")
@PropertySource("classpath:file1.properties")
@PropertySource("classpath:file2.properties")
@Configuration
public class MyConfig{

这个类有一个bean,这个bean会在应用启动时创建,它会打印Spring为属性foo.baz选择的值。

@Bean
    public Object whichProp(@Value("${foo.bar}") String fooBar, @Value("${foo.baz}") String fooBaz){
        System.out.println("Looks like foo.bar prop is set to " + fooBar  + ", foo.baz=" + fooBaz);
        return new Object();
    }

我得到的结果是:

Looks like foo.bar prop is set to defined in application.properties, foo.baz=Defined in file2.properties

我还编写了一个@Bean来转储/显示Spring属性列表(based on this answer)。

@Bean
    public Object DisplayPropertiesEnvironment(Environment environment) {
        AbstractEnvironment env = (AbstractEnvironment) environment;
        for (org.springframework.core.env.PropertySource<?> source : env.getPropertySources()) {
            if (source instanceof MapPropertySource) {
                MapPropertySource mapPropertySource = (MapPropertySource) source;
                System.out.println("Prop: " + source.getName() + "=" + mapPropertySource.getSource());
            }
        }
        return new Object();
    }

总结

我已经分享了我的想法并给出了原因。请让我知道答案。另外,如果有一个到Spring文档的URL,解释了如何工作,请分享它。

yk9xbfzb

yk9xbfzb1#

你可以参考这个Sping Boot 文档来了解所有可能的方法和加载属性的顺序。在你的情况下,如果你使用多个@PropertySource,就像文档中提到的那样
如果给定的属性键存在于多个.properties文件中,则处理的最后一个@PropertySource注解将“胜出”,并覆盖以前任何同名的键。

myss37ts

myss37ts2#

Spring总是按照文件列出的顺序读取文件。这是因为@Repeatable注解的本质,Spring不会混淆这一点。也就是说,多个相同的注解实际上是一个可重复的注解。在本例中,PropertySources
因此,在您的示例中,file1.properties中的值将覆盖datasource.propertiesfile2.properties中的值将覆盖datasource.propertiesfile1.properties

wdebmtf2

wdebmtf23#

Spring允许您在多个属性文件中定义属性值,然后通过spring.config.name属性指定要加载的属性文件。默认情况下,Spring将查找名称为www.example.com和application.yml的属性文件application.properties。
如果您在多个属性文件中定义了一个属性,那么Spring将使用最后加载的属性文件中的属性值。这意味着在以后加载的属性文件中定义的属性值将覆盖在以前加载的属性文件中定义的属性值。
例如,如果您my.property在application.propertiesapplication-prod.properties中都定义了属性www.example.com,并且指定spring.config.name=prod来加载application-prod.properties文件,那么Spring将使用在application-prod.properties中定义的my.property的值。
还可以使用spring.config.additional-location属性指定其他目录或文件以搜索属性文件。在这些位置的属性文件中定义的属性值将在spring.config.name property指定的属性文件之后加载。

相关问题