Spring Boot和多个外部配置文件

时间:2014-09-15 19:47:03

标签: java spring config spring-boot

我有多个属性文件,我想从classpath加载。 /src/main/resources下有一个默认设置,是myapp.jar的一部分。我的springcontext期望文件在类路径上。即

<util:properties id="Job1Props"
    location="classpath:job1.properties"></util:properties>

<util:properties id="Job2Props"
    location="classpath:job2.properties"></util:properties>

我还需要使用外部集覆盖这些属性的选项。我在cwd中有一个外部配置文件夹。根据spring boot doc配置文件夹应该在classpath上。但是从文档中不清楚它是否只会覆盖那里的applicaiton.properties或者配置中的所有属性。

当我对其进行测试时,只有application.properties被选中,其余属性仍会从/src/main/resources中获取。我已尝试将它们作为逗号分隔列表提供给spring.config.location,但默认设置仍未被覆盖。

如何使多个外部配置文件覆盖默认配置文件?

作为解决方法,我目前使用app.config.location(app特定属性),我通过命令行提供。即

java -jar myapp.jar app.config.location=file:./config

我将applicationcontext更改为

<util:properties id="Job2Props"
    location="{app.config.location}/job2.properties"></util:properties>

这就是我在加载Application时在文件和类路径之间进行分离的方法。
编辑:

//psuedo code

if (StringUtils.isBlank(app.config.location)) {
            System.setProperty(APP_CONFIG_LOCATION, "classpath:");
}

我真的不想使用上面的解决方法,并且让spring覆盖类路径上的所有外部配置文件,就像它对application.properties文件一样。

12 个答案:

答案 0 :(得分:117)

使用Spring Boot时,属性按以下顺序加载(请参阅Spring Boot参考指南中的Externalized Configuration)。

  1. 命令行参数。
  2. Java系统属性(System.getProperties())。
  3. 操作系统环境变量。
  4. 来自java的JNDI属性:comp / env
  5. 一个只有随机属性的RandomValuePropertySource。*。
  6. 打包jar之外的应用程序属性(application.properties包括YAML和配置文件变体)。
  7. 打包在jar中的应用程序属性(application.properties包括YAML和配置文件变体)。
  8. @Configuration类上的@PropertySource注释。
  9. 默认属性(使用SpringApplication.setDefaultProperties指定)。
  10. 解析属性时(即@Value("${myprop}")解析以相反的顺序完成(从9开始)。

    要添加不同的文件,您可以使用spring.config.location属性,该属性采用逗号分隔的属性文件列表或文件位置(目录)。

    -Dspring.config.location=your/config/dir/
    

    上面的内容将添加一个目录,将为application.properties个文件提供参考。

    -Dspring.config.location=classpath:job1.properties,classpath:job2.properties
    

    这会将2个属性文件添加到已加载的文件中。

    默认配置文件和位置在附加指定的spring.config.location之前加载,这意味着后者将始终覆盖先前设置的属性。 (另请参阅Spring Boot Reference Guide的this section)。

      

    如果spring.config.location包含目录(而不是文件),则它们应以/结尾(并且在加载之前将附加从spring.config.name生成的名称)。无论classpath:,classpath:/config,file:,file:config/的值如何,始终使用默认搜索路径spring.config.location。通过这种方式,您可以在application.properties(或使用spring.config.name选择的任何其他基本名称)中为应用程序设置默认值,并在运行时使用不同的文件覆盖它,保留默认值。

    更新: 由于spring.config.location的行为现在覆盖默认值而不是添加到默认值。您需要使用spring.config.additional-location来保留默认值。这是从1.x到2.x的行为变化

答案 1 :(得分:27)

使用Spring启动时,spring.config.location可以正常工作,只需提供逗号分隔的属性文件。

请参阅以下代码

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{

     @Value("${jdbc.host}")
        private String jdbcHostName;
     }
}

可以将jdbc.properties的默认版本放在应用程序中。可以设置外部版本。

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

根据使用spring.profiles.active属性设置的配置文件值,将获取jdbc.host的值。 所以当(在Windows上)

set spring.profiles.active=dev

jdbc.host将从jdbc-dev.properties中获取值。

代表

set spring.profiles.active=default

jdbc.host将从jdbc.properties获取值。

答案 2 :(得分:20)

看看PropertyPlaceholderConfigurer,我发现使用它比注释更清晰。

e.g。

@Configuration
public class PropertiesConfiguration {


    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("myapp_base.properties"));
        resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
        resourceLst.add(new ClassPathResource("myapp_test.properties"));
        resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));

        return ppc;
    }

答案 3 :(得分:12)

Spring boot 1.X和Spring Boot 2.X对Externalized Configuration没有提供相同的选项和行为。

M。Deinum的很好回答是关于Spring Boot 1的特殊性。 我将在此处为Spring Boot 2更新。

环境属性的来源和顺序

Spring Boot 2使用一个非常特殊的PropertySource顺序,该顺序旨在合理地覆盖值。按以下顺序考虑属性:

  
      
  • Devtools主目录上的全局设置属性   (在devtools处于活动状态时,〜/ .spring-boot-devtools.properties)。

  •   测试中的
  • @TestPropertySource注释。

  •   测试中的
  • @SpringBootTest#properties注释属性。命令   行参数。

  •   来自SPRING_APPLICATION_JSON
  • 属性(嵌入在   环境变量或系统属性)。

  •   
  • ServletConfig初始化参数。

  •   
  • ServletContext初始化参数。

  •   来自java:comp/env
  • JNDI属性。

  •   
  • Java系统属性(System.getProperties())。

  •   
  • OS环境变量。

  •   
  • 仅具有随机属性的RandomValuePropertySource。*。

  •   包装的jar之外的
  • 特定于配置文件的应用程序属性   (application-{profile}.properties和YAML变体)。

  •   
  • 打包在jar中的特定于配置文件的应用程序属性   (application-{profile}.properties和YAML变体)。

  •   
  • 打包的jar之外的应用程序属性   (application.properties和YAML变体)。

  •   
  • 打包在jar中的应用程序属性   (application.properties和YAML变体)。

  •   @PropertySource类上的
  • @Configuration注释。默认   属性(通过设置指定   SpringApplication.setDefaultProperties

  •   

要指定外部属性文件,您应该对这些选项感兴趣:

  
      包装的jar之外的
  • 特定于配置文件的应用程序属性   (application-{profile}.properties和YAML变体)。

  •   
  • 打包的jar之外的应用程序属性   (application.properties和YAML变体)。

  •   @PropertySource类上的
  • @Configuration注释。默认   属性(通过设置指定   SpringApplication.setDefaultProperties

  •   

您只能使用这三个选项之一,也可以根据需要将它们组合在一起。
例如,在非常简单的情况下,仅使用特定于配置文件的属性就足够了,但在其他情况下,您可能要同时使用特定于配置文件的属性,默认属性和@PropertySource

application.properties文件的默认位置

关于application.properties文件(和变体),默认情况下,Spring会按以下顺序加载它们并在环境中添加它们的属性:

  
      
  • 当前目录的/ config子目录

  •   
  • 当前目录

  •   
  • 类路径/ config包

  •   
  • 类路径根

  •   

从字面上看,更高的优先级是这样的:
 classpath:/,classpath:/config/,file:./,file:./config/

如何使用具有特定名称的属性文件?

默认位置并不总是足够的:默认位置,例如默认文件名(application.properties)可能不适合。此外,如在OP问题中一样,您可能需要指定多个配置文件,而不是application.properties(和变体)。
因此spring.config.name是不够的。

在这种情况下,您应该使用spring.config.location环境属性(目录位置或文件路径的逗号分隔列表)来提供显式位置。
要放心使用文件名模式,请优先选择文件路径列表而不是目录列表。
例如,这样做:

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

那是指定文件夹最冗长的方法,也是指定我们的配置文件并清楚地记录有效使用的属性的方法。

spring.config.location现在替换默认位置,而不是添加到默认位置

在Spring Boot 1中,spring.config.location参数在Spring环境中添加了指定的位置。
但是从Spring Boot 2开始,spring.config.location将Spring使用的默认位置替换为in the documentation中所述的Spring环境中的指定位置。

  

使用来配置自定义配置位置时   spring.config.location,它们将替换默认位置。对于   例如,如果spring.config.location配置了值   classpath:/custom-config/file:./custom-config/,搜索顺序   变为以下内容:

     
      
  1. file:./custom-config/

  2.   
  3. classpath:custom-config/

  4.   

spring.config.location现在是确保必须明确指定任何application.properties文件的一种方法。
对于不应该打包application.properties文件的超级JAR,这很好。

要在使用Spring Boot 2时保持spring.config.location的旧行为,可以使用新的spring.config.additional-location属性而不是spring.config.location属性,该属性仍会添加位置as stated by the documentation

  

或者,当使用来配置自定义配置位置时   spring.config.additional-location,除了   默认位置。


实践

因此,假设像在OP问题中一样,您有2个要指定的外部属性文件和uber jar中包含的1个属性文件。

仅使用您指定的配置文件:

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties   

要将配置文件添加到默认位置:

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties
在最后一个示例中,不需要

classpath:/applications.properties,因为默认位置具有默认位置,并且默认位置不会被覆盖,而是扩展。

答案 4 :(得分:6)

我遇到了同样的问题。我希望能够在启动时使用外部文件覆盖内部配置文件,类似于Spring Boot application.properties检测。 就我而言,它是一个user.properties文件,用于存储我的应用程序用户。

我的要求:

从以下位置加载文件(按此顺序)

  1. 类路径
  2. 当前目录的 / config 子目录。
  3. 当前目录
  4. 从启动时命令行参数给出的目录或文件位置
  5. 我提出了以下解决方案:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.PathResource;
    import org.springframework.core.io.Resource;
    
    import java.io.IOException;
    import java.util.Properties;
    
    import static java.util.Arrays.stream;
    
    @Configuration
    public class PropertiesConfig {
    
        private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
    
        private final static String PROPERTIES_FILENAME = "user.properties";
    
        @Value("${properties.location:}")
        private String propertiesLocation;
    
        @Bean
        Properties userProperties() throws IOException {
            final Resource[] possiblePropertiesResources = {
                    new ClassPathResource(PROPERTIES_FILENAME),
                    new PathResource("config/" + PROPERTIES_FILENAME),
                    new PathResource(PROPERTIES_FILENAME),
                    new PathResource(getCustomPath())
            };
            // Find the last existing properties location to emulate spring boot application.properties discovery
            final Resource propertiesResource = stream(possiblePropertiesResources)
                    .filter(Resource::exists)
                    .reduce((previous, current) -> current)
                    .get();
            final Properties userProperties = new Properties();
    
            userProperties.load(propertiesResource.getInputStream());
    
            LOG.info("Using {} as user resource", propertiesResource);
    
            return userProperties;
        }
    
        private String getCustomPath() {
            return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
        }
    
    }
    

    现在,应用程序使用类路径资源,但也检查其他给定位置的资源。将挑选和使用存在的最后一个资源。 我可以使用java -jar myapp.jar --properties.location = / directory / myproperties.properties启动我的应用程序,以使用浮动我的船的属性位置。

    此处的一个重要细节:使用空字符串作为@Value注释中properties.location的默认值,以避免在未设置属性时出错。

    properties.location的约定是:使用目录或属性文件的路径作为properties.location。

    如果只想覆盖特定属性,可以使用setIgnoreResourceNotFound(true)的PropertiesFactoryBean将资源数组设置为位置。

    我确信此解决方案可以扩展为处理多个文件...

    修改

    这里是我对多个文件的解决方案:)和以前一样,这可以和一个PropertiesFactoryBean结合使用。

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.PathResource;
    import org.springframework.core.io.Resource;
    
    import java.io.IOException;
    import java.util.Map;
    import java.util.Properties;
    
    import static java.util.Arrays.stream;
    import static java.util.stream.Collectors.toMap;
    
    @Configuration
    class PropertiesConfig {
    
        private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
        private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};
    
        @Value("${properties.location:}")
        private String propertiesLocation;
    
        @Bean
        Map<String, Properties> myProperties() {
            return stream(PROPERTIES_FILENAMES)
                    .collect(toMap(filename -> filename, this::loadProperties));
        }
    
        private Properties loadProperties(final String filename) {
            final Resource[] possiblePropertiesResources = {
                    new ClassPathResource(filename),
                    new PathResource("config/" + filename),
                    new PathResource(filename),
                    new PathResource(getCustomPath(filename))
            };
            final Resource resource = stream(possiblePropertiesResources)
                    .filter(Resource::exists)
                    .reduce((previous, current) -> current)
                    .get();
            final Properties properties = new Properties();
    
            try {
                properties.load(resource.getInputStream());
            } catch(final IOException exception) {
                throw new RuntimeException(exception);
            }
    
            LOG.info("Using {} as user resource", resource);
    
            return properties;
        }
    
        private String getCustomPath(final String filename) {
            return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
        }
    
    }
    

答案 5 :(得分:6)

这是一种使用弹簧启动的简单方法

<强> TestClass.java

@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {

    @Autowired
    Environment env;

    @Bean
    public boolean test() {
        System.out.println(env.getProperty("test.one"));
        return true;
    }
}

app.properties 上下文,位于所选位置

test.one = 1234

您的春季启动应用

@SpringBootApplication

public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(testApplication.class, args);
    }
}

和预定义的 application.properties 上下文

spring.profiles.active = one

您可以根据需要编写任意数量的配置类,只需设置 spring.profiles.active =配置文件名称/名称{以逗号分隔}

即可启用/禁用它们

你可以看到弹簧靴很棒,只需要一段时间熟悉,值得一提的是你也可以在你的领域使用@Value

@Value("${test.one}")
String str;

答案 6 :(得分:6)

spring boot允许我们为不同的环境编写不同的配置文件,例如我们可以为生产,qa和本地环境提供单独的属性文件

application-local.properties文件,其中包含根据我本地计算机的配置

spring.profiles.active=local

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone

spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672

rabbitmq.publish=true

同样,我们可以根据需要编写application-prod.properties和application-qa.properties多个属性文件

然后编写一些脚本来启动不同环境的应用程序,例如

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod

答案 7 :(得分:5)

我刚刚遇到了类似的问题,最终找出了原因:application.properties文件的所有权和rwx属性有误。因此,当tomcat启动时,application.properties文件位于正确的位置,但由另一个用户拥有:

$ chmod 766 application.properties

$ chown tomcat application.properties

答案 8 :(得分:0)

我发现这是一个有用的模式:

@RunWith(SpringRunner)
@SpringBootTest(classes = [ TestConfiguration, MyApplication ],
        properties = [
                "spring.config.name=application-MyTest_LowerImportance,application-MyTest_MostImportant"
                ,"debug=true", "trace=true"
        ]
)

这里我们覆盖&#34; application.yml&#34;的使用。使用&#34; application-MyTest_LowerImportance.yml&#34;还有&#34; application-MyTest_MostImportant.yml&#34;
(Spring也会查找.properties文件)

还包括作为额外奖励的调试和跟踪设置,在单独的行上,以便您可以在需要时将其注释掉;]

调试/跟踪非常有用,因为Spring会转储它加载的所有文件的名称以及它尝试加载的文件的名称。
您将在运行时在控制台中看到这样的行:

TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.properties' (file:./config/application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.xml' (file:./config/application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yml' (file:./config/application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yaml' (file:./config/application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.properties' (file:./config/application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.xml' (file:./config/application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yml' (file:./config/application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yaml' (file:./config/application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.properties' (file:./application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.xml' (file:./application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yml' (file:./application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yaml' (file:./application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.properties' (file:./application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.xml' (file:./application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yml' (file:./application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yaml' (file:./application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_MostImportant.yml' (classpath:/application-MyTest_MostImportant.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_LowerImportance.yml' (classpath:/application-MyTest_LowerImportance.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant-test.properties' (file:./config/application-MyTest_MostImportant-test.properties) resource not found

答案 9 :(得分:0)

@mxsb解决方案的修改版,允许我们定义多个文件,在我的情况下,这些文件是yml文件。

在我的application-dev.yml文件中,我添加了此配置,该配置文件允许我注入所有带有-dev.yml文件的yml。这也可以是特定文件的列表。 “ classpath:/test/test.yml,classpath:/test2/test.yml”

application:
  properties:
    locations: "classpath*:/**/*-dev.yml"

这有助于获取属性图。

@Configuration

public class PropertiesConfig {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

@Value("${application.properties.locations}")
private String[] locations;

@Autowired
private ResourceLoader rl;

@Bean
Map<String, Properties> myProperties() {
    return stream(locations)
            .collect(toMap(filename -> filename, this::loadProperties));
}

private Properties loadProperties(final String filename) {

    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .forEach(propertySource -> {
                    Map source = ((MapPropertySource) propertySource).getSource();
                    properties.putAll(source);
                });

        return properties;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
}

但是,如果像我这样,我想必须为每个概要文件分割yml文件并加载它们,然后在初始化bean之前将其直接注入spring配置。

config
    - application.yml
    - application-dev.yml
    - application-prod.yml
management
    - management-dev.yml
    - management-prod.yml

...你明白了

组件略有不同

@Component
public class PropertiesConfigurer extends     PropertySourcesPlaceholderConfigurer
    implements EnvironmentAware, InitializingBean {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfigurer.class);

private String[] locations;

@Autowired
private ResourceLoader rl;
private Environment environment;

@Override
public void setEnvironment(Environment environment) {
    // save off Environment for later use
    this.environment = environment;
    super.setEnvironment(environment);
}

@Override
public void afterPropertiesSet() throws Exception {
    // Copy property sources to Environment
    MutablePropertySources envPropSources = ((ConfigurableEnvironment) environment).getPropertySources();
    envPropSources.forEach(propertySource -> {
        if (propertySource.containsProperty("application.properties.locations")) {
            locations = ((String) propertySource.getProperty("application.properties.locations")).split(",");
            stream(locations).forEach(filename -> loadProperties(filename).forEach(source ->{
                envPropSources.addFirst(source);
            }));
        }
    });
}


private List<PropertySource> loadProperties(final String filename) {
    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        return stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .collect(Collectors.toList());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

}

答案 10 :(得分:0)

如果要覆盖application.properties文件中指定的值,则可以在运行应用程序时更改活动配置文件,并为该配置文件创建应用程序属性文件。因此,例如,让我们指定活动配置文件“ override”,然后,假设您已经在/ tmp下创建了名为“ application-override.properties”的新应用程序属性文件,那么您可以运行

java -jar yourApp.jar --spring.profiles.active="override" --spring.config.location="file:/tmp/,classpath:/" 

spring.config.location下指定的值以相反顺序求值。因此,在我的示例中,首先评估classpat,然后评估文件值。

如果jar文件和“ application-override.properties”文件位于当前目录中,则您实际上可以简单地使用

java -jar yourApp.jar --spring.profiles.active="override"

因为Spring Boot会为您找到属性文件

答案 11 :(得分:-1)

试图解决这个问题时,我遇到了很多问题。这是我的设置,

Dev Env:Windows 10, Java:1.8.0_25, 春季靴:2.0.3.RELEASE, 春季:5.0.7。发布

我发现Spring坚持了“合理的配置默认值”概念。这就是说,您必须将所有属性文件作为war文件的一部分。进入该目录后,您可以使用“ --spring.config.additional-location”命令行属性覆盖它们,以指向外部属性文件。但是,如果属性文件不是原始war文件的一部分,则将无法使用。

演示代码: https://github.com/gselvara/spring-boot-property-demo/tree/master