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()]);}