This tutorials explains you the different ways how you can do external configurations for Spring Boot applications. When you work with the real time environments, External Configurations for Spring Boot would become important for the flexibility. If you have any questions, please write it in the comments section.
Spring Boot : External Configurations for #SpringBoot http://t.co/tEFQ71UP3w pic.twitter.com/u8rwUB7iJ5
— JavaBeat (@javabeat) August 14, 2015
Applications have to store configuration of its database i.e the hostname of the db, the name of the database, user of the db, then there is information like hostname of any entities the application is dependent on, some spring related configuration overrides and so on. The spring related configurations can be found here.
There are multiple sources from where the configuration can be read from and the order in which the configuration properties are overridden is determined by Spring Boot. The order as described here is listed below:
- Command line arguments
- JNDI attributes from java:comp/env
- Java System properties (System.getProperties())
- OS environment variables
- A RandomValuePropertySource that only has properties in random.*
- Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
- Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
- Application properties outside of your packaged jar (application.properties and YAML variants)
- Application properties packaged inside your jar (application.properties and YAML variants)
- @PropertySource annotations on your @Configuration classes
- Default properties (specified using SpringApplication.setDefaultProperties)
In this post I am going to show you how to define properties using the following approaches:
- Command line arguments
- Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
- Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
- Application properties outside of your packaged jar (application.properties and YAML variants)
- Application properties packaged inside your jar (application.properties and YAML variants)
- Default properties (specified using SpringApplication.setDefaultProperties)
Lets create a basic SpringBoot application as explained in this article. In short, you would have to create a maven project and update the pom.xml as shown below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.intbittech</groupId> <version>1.0</version> <name>DocAppAPI</name> <description>RESTful API for DocApp</description> <artifactId>DocAppAPI</artifactId> <properties> <java.version>1.8</java.version> <start-class>net.javabeat.ExternalConfigApplication</start-class> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
In the above highlighted code we haven’t yet created the class ExternalConfigApplication
. It would be the starting point for our SpringBoot application. The ExternalConfigApplication
class definition is given below:
package net.javabeat; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ExternalConfigApplication { public static void main(String[] args) throws Exception { SpringApplication.run(new Object[] { ExternalConfigApplication.class }, args); } }
I will also create a component class ExternalConfigComponent
annotated with @Component
whose definition is shown below:
package net.javabeat; import javax.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class ExternalConfigComponent { private static Logger logger = LoggerFactory.getLogger(ExternalConfigComponent.class); //No properties configured yet. @PostConstruct public void postConstruct(){ //This is where we are going to print the values of the properties } }
Let us compile and run the above application as shown below:
C:\Users\Mohamed\workspace\springboot-external-config>mvn clean package ... ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3.547 s [INFO] Finished at: 2015-08-09T21:55:30+05:30 [INFO] Final Memory: 22M/218M [INFO] ------------------------------------------------------------------------ C:\Users\Mohamed\workspace\springboot-external-config>java -jar target\SpringBootExternalConfig-1.0.jar ... 2015-08-09 21:56:29.592 INFO 10444 --- [ main] net.javabeat.ExternalConfigApplication : Started ExternalConfigApplication in 1.195 seconds (JVM running for 1.675) ...
You will notice that the application starts and then terminates successfully. As this is just any other Java based command line application, it executes the application and then exits unlike Web applications.
Another way to compile and run the application in one go is to use the spring-boot maven plugin as shown below:
C:\Users\Mohamed\workspace\springboot-external-config>mvn spring-boot:run
Through out the post I am going to use the above spring-boot maven plugin to run the application.
Now let us start exploring the external configurations for Spring Boot applications.
External Configurations for Spring Boot
Default properties (specified using SpringApplication.setDefaultProperties)
SpringApplication
has an API setDefaultProperties
which accepts a Map
or a Properties
object. I am enhancing the ExternalConfigApplication
class to set the values for two properties namely: property.one
and property.two
as shown below:
package net.javabeat; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ExternalConfigApplication { private static final Logger logger = LoggerFactory.getLogger(ExternalConfigApplication.class); @Autowired private ExternalConfigComponent externalConfigComponent; public static void main(String[] args) throws Exception { SpringApplication springApplication = new SpringApplication(new Object[] { ExternalConfigApplication.class }); Map<String, Object> defaultProperties = new HashMap<String, Object>(); defaultProperties.put("property.one", "Value One"); defaultProperties.put("property.two", "Value Two"); springApplication.setDefaultProperties(defaultProperties); springApplication.run(args); } }
Let us access the two properties defined above by binding them to two fields in the ExternalConfigComponent
using the @Value
annotation as shown below:
package net.javabeat; import javax.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class ExternalConfigComponent { private static Logger logger = LoggerFactory.getLogger(ExternalConfigComponent.class); @Value("${property.one}") public String propertyOne; @Value("${property.two}") public String propertyTwo; @PostConstruct public void postConstruct(){ logger.info("Property One: " + propertyOne); logger.info("Property Two: " + propertyTwo); } }
Lets launch the above application using the spring-boot maven plugin as shown below:
$ mvn spring-boot:run ... 2015-08-10 01:46:59.530 INFO 4964 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property One: Value One 2015-08-10 01:46:59.530 INFO 4964 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Two: Value Two ...
Among the lot of text printed on the console you can find the above two lines with the value of the property.
Application properties packaged inside your jar
Another approach is to create a file by name application.properties
and package it with your jar. This file contains the key, value pairs for the properties. One can name these property files with any name, but the name has to be provided to the spring configuration property so that it can read that file. By default spring searches for application.properties
file. Let us create application.properties
in the folder src/main/resources
as shown in the image below:
And the contents of the application.properties
is as shown below:
property.two=Value Two Overridden property.three=Value Three
It contains two properties namely: property.two
and property.three
. You might wonder about the name property.two
being repeated. Yes, it is repeated and the purpose of this repetition is to show the overriding of the properties. The order of precedence of property sources has already been listed in the beginning and the Default Properties comes at the last, preceded by the application.properties file packaged in the jar. So lets see this overriding in action. Before that lets update the ExternalConfigComponent
class with the new property as shown below:
package net.javabeat; import javax.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class ExternalConfigComponent { private static Logger logger = LoggerFactory.getLogger(ExternalConfigComponent.class); @Value("${property.one}") private String propertyOne; @Value("${property.two}") private String propertyTwo; @Value("${property.three}") private String propertyThree; @PostConstruct public void postConstruct(){ logger.info("Property One: " + propertyOne); logger.info("Property Two: " + propertyTwo); logger.info("Property Three: " + propertyThree); } }
Lets launch the application and view its output:
$ mvn spring-boot:run ... 2015-08-10 02:03:34.572 INFO 920 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property One: Value One 2015-08-10 02:03:34.572 INFO 920 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Two: Value Two Overridden 2015-08-10 02:03:34.573 INFO 920 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Three: Value Three ...
You can observe above that the value of Property Two has been overridden by the value specified in the application.properties
file.
Application properties outside of your packaged jar
Above we saw application.properties
packaged inside the jar, now let us see how application.properties
file can be placed in the /config sub directory of the current directory and let Springboot load the properties defined in that file. The content of this application.properties files is given below:
property.three=Value Three Overridden property.four=Value Four
As usual there are two properties property.three
and property.four
. Let us see the updated code for ExternalConfigComponent
below:
//Add this below along with the other property declarations @Value("${property.four}") private String propertyFour; //Append the below to the postConstruct() method logger.info("Property Four: " + propertyFour);
Running the application gives us the below output:
.... 2015-08-14 17:06:13.469 INFO 12624 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property One: Value One 2015-08-14 17:06:13.470 INFO 12624 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Two: Value Two Overridden 2015-08-14 17:06:13.471 INFO 12624 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Three: Value Three Overridden 2015-08-14 17:06:13.472 INFO 12624 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Four: Value Four ...
You will notice in the highlighted lines above that the property defined in the application.properties
file defined inside the Jar has been overridden by the application.properties defined outside the jar in the /config sub directory.
Profile-specific application properties packaged inside your jar
We can have multiple values for a property depending on the environment the application is running in i.e dev environment or production environment. To support this feature Springboot has concept called profiles. One can create a profile by name local for local environment, then dev for development environment and so on. So the names of the property files will now be application-local.properties and application-dev.properties respectively.
The profile can be selected by setting the profile name in the Spring property spring.profiles.active
. We can set this value using any one of the approaches defined here, and we would use the approach to set the value via command line. But before we show that let us see the contents of the application-local.properties
:
property.four=Value Four Overridden property.five=Value Five
Let us update the ExternalConfigComponent
to accomodate the new property property.five
with the below code:
//Add this below along with the other property declarations @Value("${property.five}") private String propertyFive; //Append the below to the postConstruct() method logger.info("Property Five: " + propertyFive);
Let us run the application by using the command: mvn spring-boot:run -Dspring.profiles.active=local
. After the application is run successfully you will see the below output:
... 2015-08-14 17:37:29.348 INFO 8760 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property One: Value One 2015-08-14 17:37:29.348 INFO 8760 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Two: Value Two Overridden 2015-08-14 17:37:29.348 INFO 8760 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Three: Value Three Overridden 2015-08-14 17:37:29.348 INFO 8760 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Four: Value Four Overridden 2015-08-14 17:37:29.348 INFO 8760 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Five: Value Five ...
You can notice that the property property.four
from the /config/application.properties
has been overridden by application-local.properties
and also the new property property.five
provided by the new properties files.
Profile-specific application properties outside of your packaged jar
Just as we saw with application.properties
placed in the jar and outside the jar in a sub directory, we can do the same with profile specific application properties. Let us create application-local.properties with the below data and store it in the /config sub directory created earlier:
property.five=Value Five Overridden property.six=Value Six
And the below are the updates to the ExternalConfigComponent
:
//Add this below along with the other property declarations @Value("${property.six}") private String propertySix; //Append the below to the postConstruct() method logger.info("Property Six: " + propertySix);
Let us run the application by using the command: mvn spring-boot:run -Dspring.profiles.active=local
. After the application is run successfully you will see the below output:
... 015-08-14 17:51:59.469 INFO 11564 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Five: Value Five Overridden 2015-08-14 17:51:59.469 INFO 11564 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Six: Value Six ..
You can notice the above two lines printed among other lines in the output after executing the program. So the application-local.properties
file in the /config sub directory has overridden the property.five
defined in the application-local.properties
packaged in the jar.
Command line arguments
The value for these properties are passed via command line while launching the application. I am going to configure two properties by name: property.six
and property.seven
and bind them to our ExternalConfigComponent
class as shown below:
//Add this below along with the other property declarations @Value("${property.seven}") private String propertySeven; //Append the below to the postConstruct() method logger.info("Property Seven: " + propertySeven);
Lets try to launch the application by passing the values for the above two configuration properties as shown below:
C:\Users\Mohamed\workspace\springboot-external-config>mvn spring-boot:run -Dspring.profiles.active=local -Dproperty.six="Value Six Overridden" -Dproperty.seven="Value Seven" ... 2015-08-14 19:24:23.430 INFO 5584 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Six: Value Six Overridden 2015-08-14 19:24:23.430 INFO 5584 --- [lication.main()] net.javabeat.ExternalConfigComponent : Property Seven: Value Seven ...
You can see the values of the configuration properties (highlighted above) printed on the console among other outputs and also see that the value for property.six
has been overridden by the value passed as a command line argument.
With this we come to an end of the article. We have shown you different ways we can setup properties in Spring Boot and also how the order/precedence of the sources override the values defined in different property sources. If you have any questions on External Configurations for Spring Boot, please write it in the comments section.
The complete code can be accessed from Github here. If you want to run the complete code then you have to make use of the command: mvn spring-boot:run -Dspring.profiles.active=local -Dproperty.six="Value Six Overridden" -Dproperty.seven="Value Seven"
.