PropertySourcesPlaceholderConfigurer not registering with Environment in a SpringBoot Project PropertySourcesPlaceholderConfigurer not registering with Environment in a SpringBoot Project spring spring

PropertySourcesPlaceholderConfigurer not registering with Environment in a SpringBoot Project


The issue here is the distinction between PropertySourcesPlaceholderConfigurer and StandardServletEnvironment, or Environment for simplicity.

The Environment is an object that backs the whole ApplicationContext and can resolve a bunch of properties (the Environment interface extends PropertyResolver). A ConfigurableEnvironment has a MutablePropertySources object which you can retrieve through getPropertySources(). This MutablePropertySources holds a LinkedList of PropertySource objects which are checked in order to resolve a requested property.

PropertySourcesPlaceholderConfigurer is a separate object with its own state. It holds its own MutablePropertySources object for resolving property placeholders. PropertySourcesPlaceholderConfigurer implements EnvironmentAware so when the ApplicationContext gets hold of it, it gives it its Environment object. The PropertySourcesPlaceholderConfigurer adds this Environment's MutablePropertySources to its own. It then also adds the various Resource objects you specified with setLocation() as additional properties. These Resource objects are not added to the Environment's MutablePropertySources and therefore aren't available with env.getProperty(String).

So you cannot get the properties loaded by the PropertySourcesPlaceholderConfigurer into the Environment directly. What you can do instead is add directly to the Environment's MutablePropertySouces. One way is with

@PostConstructpublic void setup() throws IOException {    Resource resource = new FileSystemResource("spring.properties"); // your file    Properties result = new Properties();    PropertiesLoaderUtils.fillProperties(result, resource);    env.getPropertySources().addLast(new PropertiesPropertySource("custom", result));}

or simply (thanks @M.Deinum)

@PostConstructpublic void setup() throws IOException {    env.getPropertySources().addLast(new ResourcePropertySource("custom", "file:spring.properties")); // the name 'custom' can come from anywhere}

Note that adding a @PropertySource has the same effect, ie. adding directly to the Environment, but you're doing it statically rather than dynamically.


In SpringBoot it's enough to use @EnableConfigurationProperties annotation - you don't need to setup PropertySourcesPlaceholderConfigurer.

Then on POJO you add annotation @ConfigurationProperties and Spring automatically injects your properties defined in application.properties.

You can also use YAML files - you just need to add proper dependency (like SnakeYaml) to classpath

You can find detailed example here: http://spring.io/blog/2013/10/30/empowering-your-apps-with-spring-boot-s-property-support


I achieved this during PropertySourcesPlaceholderConfigurer instantiation.

@Beanpublic static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurerBean(Environment env) {    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();    YamlPropertiesFactoryBean yamlFactorybean = new YamlPropertiesFactoryBean();    yamlFactorybean.setResources(determineResources(env));    PropertiesPropertySource yampProperties = new PropertiesPropertySource("yml", yamlFactorybean.getObject());    ((AbstractEnvironment)env).getPropertySources().addLast(yampProperties);    propertySourcesPlaceholderConfigurer.setProperties(yamlFactorybean.getObject());    return propertySourcesPlaceholderConfigurer;}private static Resource[] determineResources(Environment env){    int numberOfActiveProfiles = env.getActiveProfiles().length;    ArrayList<Resource> properties =  new ArrayList(numberOfActiveProfiles);    properties.add( new ClassPathResource("application.yml") );    for (String profile : env.getActiveProfiles()){        String yamlFile = "application-"+profile+".yml";        ClassPathResource props = new ClassPathResource(yamlFile);        if (!props.exists()){            log.info("Configuration file {} for profile {} does not exist");            continue;        }        properties.add(props);    }    if (log.isDebugEnabled())        log.debug("Populating application context with properties files: {}", properties);    return properties.toArray(new Resource[properties.size()]);}