Search code examples
springspring-bootvault

how can application yaml value inject at runtime in spring boot?


I want to change the value of application.yaml at loading time.

ex) application.yaml

user.name: ${name}

Here, I want to put this value by calling an external API such as a vault, rather than a program argument when the jar is executed with the name value.

First of all, I think I need to write code that implements EnvironmentPostProcessor and calls external API, but I don't know how to inject that value. can I get help?

public class EnvironmentConfig implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment,
        SpringApplication application) {
        // API CAll
        
        // how can inject yaml value??
    }
}

I don't know which way to orient myself.


Solution

  • OPTION 1: doing it via EnvironmentPostProcessor:

    assuming you have registered you EnvironmentPostProcessor in /resources/META-INF/spring.factories file:

    org.springframework.boot.env.EnvironmentPostProcessor=package.to.environment.config.EnvironmentConfig

    all you need is to add your custom PropertySource:

    public class EnvironmentConfig implements EnvironmentPostProcessor {
    
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                                           SpringApplication application) {
            environment.getPropertySources()
                    .addFirst(new CustomPropertySource("customPropertySource"));
        }
    }
    
    public class CustomPropertySource extends PropertySource<String> {
        public CustomPropertySource(String name) {
            super(name);
        }
    
        @Override
        public Object getProperty(String name) {
            if (name.equals("name")) {
                return "MY CUSTOM RUNTIME VALUE";
            }
            return null;
        }
    }
    
    
    

    OPTION 2: doing it via PropertySourcesPlaceholderConfigurer:

    A class that is responsible for resolving these palceholders is a BeanPostProcessor called PropertySourcesPlaceholderConfigurer (see here).

    So you could override it and provide you custom PropertySource that would resolve your needed property like so:

    @Component
    public class CustomConfigurer extends PropertySourcesPlaceholderConfigurer {
    
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, ConfigurablePropertyResolver propertyResolver) throws BeansException {
            ((ConfigurableEnvironment) beanFactoryToProcess.getBean("environment"))
                    .getPropertySources()
                    .addFirst(new CustomPropertySource("customPropertySource"));
            super.processProperties(beanFactoryToProcess, propertyResolver);
        }
    }