Jason
Jason

Reputation: 2076

Spring Environment - multiple?

I am confused about how Spring Environment works. I thought it is basically a singleton bean in the ApplicationContext and anytime I load PropertySources into my AppCtx, they combine into this single Environment automatically. However, I am seeing this logged many times in my app, which means the constructor of AbstractEnvironment is getting called many times:


2015-01-06 12:16:26,858 DEBUG (main) [org.springframework.core.env.StandardEnvironment] Adding [systemProperties] PropertySource with lowest search precedence
2015-01-06 12:16:26,858 DEBUG (main) [org.springframework.core.env.StandardEnvironment] Adding [systemEnvironment] PropertySource with lowest search precedence
2015-01-06 12:16:26,858 DEBUG (main) [org.springframework.core.env.StandardEnvironment] Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]

The results are that I do things like:

@Autowire
Environment environment;

String propertyIExpect = environment.getProperty("myprop");

And I get an instance of the Environment, but no properties I expected to be present are in it.

I expected them to have been added to this auto-wired Environment when I added this XML to my Spring Boot application context:

<context:property-placeholder location="classpath:/spring/environment/${ctms.env}/application.properties" order="1"/>
<context:property-placeholder location="classpath:build.info" order="2"/>

Then again, sometimes the Environment properties are there as shown in this logging:


2015-01-06 12:16:37,433 TRACE (main) [org.springframework.core.env.PropertySourcesPropertyResolver] getProperty("ctms.env", String)
2015-01-06 12:16:37,433 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'ctms.env' in [servletConfigInitParams]
2015-01-06 12:16:37,433 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'ctms.env' in [servletContextInitParams]
2015-01-06 12:16:37,433 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'ctms.env' in [systemProperties]
2015-01-06 12:16:37,433 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Found key 'ctms.env' in [systemProperties] with type [String] and value 'dev'
2015-01-06 12:16:37,438 DEBUG (main) [org.springframework.core.env.MutablePropertySources] Adding [environmentProperties] PropertySource with lowest search precedence
2015-01-06 12:16:37,438 INFO  (main) [org.springframework.context.support.PropertySourcesPlaceholderConfigurer] Loading properties file from class path resource [spring/environment/dev/application.properties]
2015-01-06 12:16:37,438 DEBUG (main) [org.springframework.core.env.MutablePropertySources] Adding [localProperties] PropertySource with lowest search precedence
2015-01-06 12:16:37,443 TRACE (main) [org.springframework.core.env.PropertySourcesPropertyResolver] getProperty("database.connection.url", String)
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [environmentProperties]
2015-01-06 12:16:37,443 TRACE (main) [org.springframework.core.env.PropertySourcesPropertyResolver] getProperty("database.connection.url", String)
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [servletConfigInitParams]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [servletContextInitParams]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [systemProperties]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [systemEnvironment]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [random]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [applicationConfig: [classpath:/application.properties]]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Could not find key 'database.connection.url' in any property source. Returning [null]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Searching for key 'database.connection.url' in [localProperties]
2015-01-06 12:16:37,443 DEBUG (main) [org.springframework.core.env.PropertySourcesPropertyResolver] Found key 'database.connection.url' in [localProperties] with type [String] and value 'jdbc:oracle:thin:@somehost:someport/foo'

NOTE: I am also seeing this in the Spring Boot logs 2 times:

12:19:03,387 INFO  [TomcatEmbeddedServletContainer] Tomcat started on port(s): 8080/http

I would've expected this one time at the end. Perhaps this is related? Am I somehow creating multiple ApplicationContexts in my Spring Boot app?

Upvotes: 1

Views: 4719

Answers (2)

Jason
Jason

Reputation: 2076

From the advice posted here, I no longer load the properties file: classpath:/spring/${ctms.env}/application.properties from a <context:property-placeholder> XML.

This is how I resolved my Environment properties issue:

Since ${ctms.env} is essentially the environment we are running in and also reflected in a Spring active profile (e.g., dev, test, stage, prod), I ended up using Spring Boot's feature to auto-load active profile properties files "by convention" for me.

To clarify, this Spring Boot feature will look for .properties files in specific locations based on the active profiles. Like this:

For a Spring Active Profile = "foo", it would auto-load this file, if it exists:

WEB-INF/classes/config/application-foo.properties

For my solution, I re-locate and re-name the properties file in my Spring Boot WAR to like this:

/WEB-INF/classes/config/application-${ctms-env}.properties

It basically ends up being something like: For "dev" Spring Active Profile:

/WEB-INF/classes/config/application-dev.properties

For "test" Spring Active Profile:

/WEB-INF/classes/config/application-test.properties

For "stage" Spring Active Profile:

/WEB-INF/classes/config/application-stage.properties

etc.

I didn't have to re-write any properties files. I just had to re-package them the way Spring Boot "conventions" want to find/load them. And, then of course, stop loading via the XML way. And it works great.

Upvotes: 0

Dave Syer
Dave Syer

Reputation: 58094

An XML <context:property-placeholder/> is not added to the Environment. The DEBUG logs are just noise, so probably ignorable. If you need it in the Environment then use the Spring Boot APIs to set the property locations (or possibly us @PropertySource).

Upvotes: 1

Related Questions