Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring property substitution for test and production

Tags:

spring

I ran into this for property substitution in spring

<context:property-placeholder location="esb-project-config.properties"/>

but unfortunately, we don't want this in the xml file as we want to re-use the file in our tests but swap in the test.properties file for test. ie. we want to test all the production bindings but with properties that are suitable for test like localhost for instance. How can we load the ApplicationContext but with different properties files?

thanks, Dean

like image 733
Dean Hiller Avatar asked Feb 27 '12 18:02

Dean Hiller


People also ask

How do I use YAML instead of properties in spring boot?

Since I use spring-boot-starter the SnakeYAML library is already in the classpath, and SpringApplication should use the YAML version automatically. The SpringApplication class will automatically support YAML as an alternative to properties whenever you have the SnakeYAML library on your classpath.

Which property is given precedence by spring?

Spring Boot application converts the command line properties into Spring Boot Environment properties. Command line properties take precedence over the other property sources. By default, Spring Boot uses the 8080 port number to start the Tomcat.

How do I set environment properties in spring boot?

Environment-Specific Properties File. If we need to target different environments, there's a built-in mechanism for that in Boot. We can simply define an application-environment. properties file in the src/main/resources directory, and then set a Spring profile with the same environment name.

What is @DynamicPropertySource?

@DynamicPropertySource instead is used to: make it easier to set configuration properties from something else that's bootstrapped as part of running an integration test. This helps also setting up integration tests with Test Containers, getting rid of a lot of boilerplate code.


5 Answers

several approaches:


1. 'Order' Property

in src/main/resources/your-conf.xml

<context:property-placeholder 
         location="classpath:esb-project-config.properties"
         order="1"/>

in src/test/resources/your-test-config.xml

<context:property-placeholder 
         location="classpath:esb-project-config.properties"
         order="0"/>

If you running your test with src/test/resources as a test classpath, the above will ensure to override src/main/resources/esb-project-config.properties with the src/test/resources/esb-project-config.properties.

This will override the whole property-placeholder though, so you would have to provide all the properties needed in your application in for this test property-placeholder. e.g.

<context:property-placeholder 
         location="classpath:esb-project-config.properties,
                   classpath:some-other-props-if-needed.properties"
         order="0"/>

2. PropertyOverrideConfigurer

 <context:property-override 
          location="classpath:esb-project-config.test.properties"/>

to override certain individual properties. Some examples here


3. System Variables

You can use a prefix to control environment specific properties, this can be done by using system variables:

 <context:property-placeholder 
          location="${ENV_SYSTEM:dev}/esb-project-config.properties"/>

In this case it will always look under:

 <context:property-placeholder 
          location="dev/esb-project-config.properties"/>

by default, unless a ENV_SYSTEM system variable is set. If it is set to qa, for example, it will automatically look under:

 <context:property-placeholder 
          location="qa/esb-project-config.properties"/>

4. Spring Profiles

Another approach is to make beans profile specific. For example:

<beans profile="dev">
  <context:property-placeholder 
           location="esb-project-config.dev.properties"/>
</beans>

<beans profile="qa">
  <context:property-placeholder 
           location="esb-project-config.qa.properties"/>
</beans>

The appropriate esb-project-config will loaded depending on a profile set. For example this will load esb-project-config.dev.properties:

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.getEnvironment().setActiveProfiles( "dev" );
ctx.load( "classpath:/org/boom/bang/config/xml/*-config.xml" );
ctx.refresh();

  • NOTE: "System Variables" and "System Profiles" approaches are usually used to switch between different environments rather than just "dev <==> test" in dev mode, but still are useful capabilities to be aware of.
like image 114
tolitius Avatar answered Sep 24 '22 11:09

tolitius


Put the property-placeholder configuration in an extra spring xml configuration file.

For example:

  • applicationContext.xml -- for the normal configration without any property-placeholder configuration
  • applicationContext-config.xml -- contains only a property-placeholder that load the production config file.
  • testApplicationContext.xml. This file includes the applicationContext.xml and uses a property-placeholder with an other properties file.

In a Web App you could load all production spring context files with this pattern applicationContext*.xml.

For the tests you need only to load testApplicationContext.xml this will include the normal config, but with other properties.

like image 31
Ralph Avatar answered Sep 26 '22 11:09

Ralph


  • On the context tag you can indicate that if a properties file does not exist it does not need to fail.
  • Property files are loaded in the order that they are declared. (This might also be a property to declare on the tag. Not sure)
  • If a property is declared multiple times, the last loaded value is used.

We use these three features as follows:

We declare two property files:

classpath:esb-project-config.properties,
classpath:esb-project-config-override.properties

The first property file contains sensible defaults and development configuration. This file is part of your application.

The second property file is a file that is available on the test classpath or even the production classpath of the application server. This file is external of the application That way we can override properties for each environment and have just one version of our application.

So here is the example of the properties we use:

    <context:property-placeholder 
       ignore-resource-not-found="true" ignore-unresolvable="true" 
       location="classpath:esb-project-config.properties,classpath:esb-project-config-override.properties" />
like image 23
tom Avatar answered Sep 25 '22 11:09

tom


My preferred method, as added by spring 3.1, is as follows:

In your *-context.xml:

<context:property-placeholder location="classpath:/web-${spring.profiles.active}.properties" />

and in web.xml:

<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>prod</param-value>
</context-param>

You can then specify the environment at runtime, for example:

mvn -Dspring.profiles.active=dev jetty:run

Or however you pass arguments to your container.

like image 33
Vetsin Avatar answered Sep 24 '22 11:09

Vetsin


It seems:

  <beans profile="dev">
    <context:property-placeholder location="classpath:config/dev.properties"/>
  </beans>
  <beans profile="prod">
    <context:property-placeholder location="classpath:config/prod.properties"/>
  </beans>

It doesn't work. But you can do:

<context:property-placeholder location="classpath:config_${spring.profiles.active}.properties" />
like image 31
Sebastien Lorber Avatar answered Sep 25 '22 11:09

Sebastien Lorber