1

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?

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Jason
  • 2,006
  • 3
  • 21
  • 36
  • You will usually see 2 contexts: servlet & root. However, I would be suspicious of what else might be in that "Spring Boot" XML configuration file and how it's being loaded. The existence of such a file could indicate that it's not a Spring Boot application. If it is a Spring Boot app and that is a Spring XML configuration file, then you're likely to be loading two contexts (servlet & root) based on that file and Spring Boot will also be loading a servlet and root context. – Steve Jan 07 '15 at 09:40
  • 1
    Generally your xml is ignored when using Spring Boot and you should just use `@PropertySource` to load additional property files. However the easiest solution is to simply add your properties to the default loaded `application.properties` file. – M. Deinum Jan 07 '15 at 10:29
  • @Steve - Oh it's definitely a Spring Boot app. In fact, you might say its a case study in how to move a legacy app from JBoss EAP & Spring to Spring Boot alone (w/ embedded JMS, JNDI, JTA, and JCA). My app is 10 years old, ~500K lines, and over 250 Spring beans in XML with no time to re-factor them all to Java. No Web or Dispatcher XMLs. But, the old XML-based beans loading into Spring Boot with ImportResource on a Configuration annotated class. They load just fine! It is this one Environment detail that has confused me. That is the only thing that is not loading fine. – Jason Jan 11 '15 at 17:06

2 Answers2

1

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).

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
0

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.

Jason
  • 2,006
  • 3
  • 21
  • 36