Dimnox
Dimnox

Reputation: 471

Spring Boot override properties from a user specific file

I work on a SpringBoot application which has to run on different environments. The property files are created and once I modify the environment the default values are overridden with the proper ones. That's okay.

In the next step I want to check whether the logged in user System.getProperty("user.name") has a custom property file. If so, these properties must be overriden with his ones. So the steps should be (let's say the active profile is dev):

  1. Load application.properties
  2. Load and override properties from application-dev.properties
  3. In case the user has a custom property file (user.properties), load this and override the properties

I read many topcis and found two possible solutions, but none of them worked.

  1. Add the annotation @PropertySource("user.properties") to a configuration class, which should load the user specific property file and override the values. For testing purposes, I added server.port=1234 to user.properties, but this was ignored.
  2. Create a custom PropertyPlaceholderConfigurer. Although this bean was created successfully, the server port wasn't changed.

`

@Bean
public PropertyPlaceholderConfigurer propertyPlaceholder() {
    PropertyPlaceholderConfigurer propertyPlaceholder = new PropertyPlaceholderConfigurer();
    propertyPlaceholder.setLocations(
            new ClassPathResource("application.properties"),
            new ClassPathResource("application-dev.properties"),
            new ClassPathResource("user.properties"));

    propertyPlaceholder.setIgnoreResourceNotFound(true);
    propertyPlaceholder.setIgnoreUnresolvablePlaceholders(true);
    return propertyPlaceholder;
}

I don't know how to go forward. So any idea is really welcomed.

Update: I've justed pushed the demo code to GitHub. Maybe is helps to find the solution: https://github.com/aszidien/springboot.

Upvotes: 1

Views: 4763

Answers (1)

Strelok
Strelok

Reputation: 51481

Correct way to customise environment in Spring Boot is with an EnvironmentPostProcessor that will run very early in ApplicationContext start-up and allow you to manage the property sources.

Step 1. Create file src/main/resources/META-INF/spring.factories with the following:

org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.YourEnvironmentPostProcessor

Step 2. As an example create a file src/main/resources/custom.properties with:

server.port=8081

Step 3. Now create you post processor class

package com.example;

public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {

  private final PropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader();

  @Override
  public void postProcessEnvironment(ConfigurableEnvironment environment,
                                     SpringApplication application) {
    Resource path = new ClassPathResource("custom.properties");
    // ^^^ here you can create the resource however you want
    // construct the name from a user name, use FileSystemResource, anything
    // for example you can ask users to place a file in their home 
    // directory named "my-application.properties" and load it like so

    // Resource path = new FileSystemResource(Paths.get(System.getProperty("user.home"),"my-application.properties").toString());

    PropertySource<?> propertySource = loadProps(path);
    environment.getPropertySources().addFirst(propertySource);
  }

  private PropertySource<?> loadProps(Resource path) {
    if (!path.exists()) {
      throw new IllegalArgumentException("Resource " + path + " does not exist");
    }
    try {
      return this.loader.load("custom-resource", path, null);
    }
    catch (IOException ex) {
      throw new IllegalStateException(
          "Failed to load props configuration from " + path, ex);
    }
  }

}

Now when you run your application the port will change to 8081 and any other properties will override the defaults provided in your main properties.

Upvotes: 1

Related Questions