从application.yml读取属性时,将忽略弹簧配置文件

时间:2018-11-02 11:11:05

标签: java spring

我有这段代码可以扫描Spring上下文:

public void scan() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    context.register(SomeConfig.class);
    context.refresh();
}

我需要从application.yml文件中读取属性,因此在SomeConfig类中,我有以下内容:

@Configuration
@PropertySource(value = "classpath:application.yml", factory = YamlPropertyLoaderFactory.class)
public class SomeConfig {
  //some beans
}

(我已经从here复制了YamlPropertyLoaderFactory类)

application.yml是一个典型的Spring Boot文件,具有一些配置文件属性和默认配置文件:

spring:
  profiles:
    active: p1

---

spring:
   profiles: p1

file: file1.txt

---

spring:
   profiles: p2

file: file2.txt

在某些bean中,我正在使用file来读取@Value属性。

运行应用程序时,我传递了-Dspring.profiles.active=p1变量,但出现错误:

  

无法解析值“ $ {file}”中的占位符“文件”

(即使我没有通过任何配置文件,它也应该起作用,因为application.yml的默认配置文件设置为p1)

如果我从application.yml删除所有配置文件配置,则可以正常运行:

file: file1.txt

因此,这意味着上下文扫描未读取配置文件变量。

此外,如果我“以编程方式”设置了活动配置文件,它也不会解析属性:

context.getEnvironment().setActiveProfiles("p1");

3 个答案:

答案 0 :(得分:2)

您引用的YamlPropertyLoaderFactory具有以下代码:

public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }

        return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null);
    }
}

YamlPropertySourceLoader.load()方法的第三个参数实际上是您想要属性的配置文件名称。当此示例传递null时,它仅从yml文件返回一组属性,而不是针对特定配置文件。

spring:
  profiles:
    active: p1

---

我认为在YamlPropertyLoaderFactory中选择有效的个人资料名称并不容易,尽管您可以尝试类似...

public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }

        String activeProfile = System.getProperty("spring.profiles.active");
        return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), activeProfile);
    }
}

或者在yml文件中有有效的配置文件名称的情况下,可以使用null调用YamlPropertySourceLoader().load以获取spring.profiles.active属性,然后再次调用它以加载所需的yml文件的实际部分

public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }
        PropertySource<?> source = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null);
        String activeProfile = source.getProperty("spring.profiles.active");
        return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), activeProfile);
    }
}

YamlPropertySourceLoader已于2018年2月(YamlPropertySourceLoader blame view in Git repo)更改。现在,它返回propertySource的列表,并且在load方法上没有第三个参数。

假设yml文件中具有spring.profiles.active属性,则可以使用较新版本的YamlPropertySourceLoader

执行以下操作
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }
        List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
        for (PropertySource<?> checkSource : sources) {
            if (checkSource.containsProperty("spring.profiles.active")) {
                String activeProfile = (String) checkSource.getProperty("spring.profiles.active");
                for (PropertySource<?> source : sources) {
                    if (activeProfile.trim().equals(source.getProperty("spring.profiles"))) {
                        return source; 
                    }
                }
            }
        }
        return sources.get(0);
    }

}

答案 1 :(得分:0)

@pcoates我尝试使用YamlPropertySourceLoader的较新版本仍然无法加载配置文件。

在以下情况下始终失败,源返回了2个元素,而没有源“ spring.profiles.active”,

if (checkSource.containsProperty("spring.profiles.active"))

下面是我的yaml和yaml属性加载器的配置

  profiles: dev
  excelPath :  /data/excel
  excecutionPath: http://localhost:8080/server/execute
  memberIP: localhost
  profilerPortNum: 3031

--- 

spring:
  profiles: uat
  excelPath :  /data/uat/excel
  excecutionPath: http://localhost:8080/server/execute
  memberIP: localhost
  profilerPortNum: 3032```

@Configuration
@PropertySource(value = "classpath:application.yml", factory = YamlPropertyLoaderFactory.class)
public class ReadYamlProperties {
}


答案 2 :(得分:-1)

要仅为特定配置文件设置属性,正确的缩进为:

spring:
   profiles: p1
   file: file1.txt

在上述情况下,您可以使用file1.txt EL访问${spring.file}