Search code examples
javaspringenvironment-variablessystem-properties

Environment variables not converted to system properties


Working on a legacy Spring based application (Spring 4.3), I have a strange behavior: environment variables are not resolved by Spring. For example I have this environment variable: HOST_SERVICE_BASE_URL, when I refer to it in the application with ${host.service.base.url} the property is not resolved and the application fails during start up.

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'host.service.base.url' in value "${host.service.base.url}

I defined these beans for property resolution:

    @Bean
    public PropertiesFactoryBean applicationProperties( ResourceLoader resourceLoader ) {
        PropertiesFactoryBean propertiesFactory = new PropertiesFactoryBean();
        propertiesFactory.setLocations( resourceLoader.getResource( "/WEB-INF/config/application.properties" ),
                    resourceLoader.getResource( "/WEB-INF/config/application-dev.properties" ) );
        return propertiesFactory;
    }

And

    <bean id="dataConfigPropertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="searchSystemEnvironment" value="true"/>
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="properties" ref="applicationProperties"/>
    </bean>

Solution

  • You are using the (now deprecated) PropertyPlaceholderConfigurer while that can consult the system environment it lacks the feature of mapping those properties to values. I.e HOST_SERVICE_BASE_URL isn't mapped as host.service.base.url.

    That support is only available in the SystemEnvironmentPropertySource which is automatically registered and consulted when using the PropertySourcesPlaceholderConfigurer (recommended as of Spring 5.2, but available since 3.1).

    <bean id="dataConfigPropertyConfigurer"
              class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="properties" ref="applicationProperties"/>
    </bean>
    

    Or in Java to replace the applicationProperties bean and XML portion.

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
      PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
      configurer.setLocations({"/WEB-INF/config/application.properties", /WEB-INF/config/application-dev.properties"});
      configurer.setIgnoreResourceNotFound(true);
      return configurer;
    }
    

    Or if you really stick with XML use the <context:property-placeholder /> tag, which automatically does this.

    <context:property-placeholder properties="applicationProperties" ignore-resource-not-found="true" />
    

    or

    <context:property-placeholder locations="/WEB-INF/config/application.properties,/WEB-INF/config/application-dev.properties" ignore-resource-not-found="true" />