Can a PropertiesFactoryBean read a value from application.yml?

My project has a dependency that requires a set of properties object that can be read by @Value annotations:

@Value("#{myProps['property.1']}")

To do this in JavaConfig, I use the following:

@Bean(name="myProps")
public static PropertiesFactoryBean mapper() {
    PropertiesFactoryBean bean = new PropertiesFactoryBean();
    bean.setLocation(new ClassPathResource("myprops.properties"));
    return bean;
}

This works as expected. My properties are as follows:

property.1=http://localhost/foo/bar
property.2=http://localhost/bar/baz
property.3=http://localhost/foo/baz

I am using Spring Boot for this project, so I would like to do something like the following:

myprops.properties:
    property.1=${base.url}/foo/bar
    property.2=${base.url}/bar/baz
    property.3=${base.url}/foo/baz

Then I could customize base.url based on different profiles.

application.yml:

    base:
      url: http://localhost

    ---
    spring:
      profiles: staging
    base:
      url: http://staging

    ---
    spring:
      profiles: production
    base:
      url: http://production

I tried to do this and it does not work. As a workaround, I created three different .properties files (myprops.properties, myprops-staging.properties, etc.) and loaded them with three different @Configuration classes. It works, but it seems cumbersome.

@Configuration
public class DefaultConfiguration {

    @Bean(name="myProps")
    public static PropertiesFactoryBean mapper() {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new ClassPathResource("myprops.properties"));
        return bean;
    }
}

@Configuration
@Profile("staging")
public class StagingConfiguration {

    @Bean(name="myProps")
    public static PropertiesFactoryBean mapper() {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new ClassPathResource("myprops-staging.properties"));
        return bean;
    }
}

@Configuration
@Profile("production")
public class ProductionConfiguration {

    @Bean(name="myProps")
    public static PropertiesFactoryBean mapper() {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new ClassPathResource("myprops-production.properties"));
        return bean;
    }
}

PropertiesFactoryBean application.yml? , JavaConfig?

+3
2

, , :

@Value("${base.url}")
private String baseUrl;

@Bean(name = "myProps")
public PropertiesFactoryBean mapper() throws IOException {
    PropertiesFactoryBean bean = new PropertiesFactoryBean();
    bean.setLocation(new ClassPathResource("myprops.properties"));
    bean.afterPropertiesSet();

    // replace ${base.url} in values
    Properties props = bean.getObject();
    Enumeration names = props.propertyNames();

    while (names.hasMoreElements()) {
        String name = names.nextElement().toString();
        String value = props.getProperty(name);
        if (value.contains("${base.url}")) {
            props.setProperty(name, value.replace("${base.url}", baseUrl));
        }
    }

    bean.setLocalOverride(true);
    bean.setProperties(props);
    bean.afterPropertiesSet();

    if (log.isDebugEnabled()) {
        log.debug("Base URL: " + baseUrl);
    }

    return bean;
}
+2

100%, , , , , YAML ? "application.yml"? - , - , @PropertySource SpringApplication ( , , , ).

+1

All Articles