Spring's Application.Properties: Friend or Foe?
Take a look at Spring's application.properties file and whether or not it is ''friend'' or ''foe?''
Join the DZone community and get the full member experience.
Join For FreeIn this post, we analyze Spring's application.properties file and whether or not it is "friend" or "foe." Let's take a closer look.
You may also like: What Are Common Application.Properties in Spring Boot?
To get started, let's create a simple Spring Boot web application. A common way to create a new Spring application is to visit the Spring Initialzr website and generate one.
Once downloaded and imported into IntelliJ, it will look like this:
In this case, the default is application.properties, but it could just as easily have been it’s YAML variant.
Add a property to application.properties:
myapp.welcome.message=Thank you for visiting us today
Update build.gradle to make it an executable web app:
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
...
}
Add a simple controller to the DemoApplication
:
@RestController
@SpringBootApplication
public class DemoApplication {
@Value("${myapp.welcome.message}")
private String welcomeMessage;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/{user}")
public String welcome(@PathVariable final String user) {
return welcomeMessage + " " + user;
}
}
Build the artifact:
./gradlew clean build
Run the application (located in build/libs):
java -jar demo-0.0.1-SNAPSHOT.jar
And if you go to http://localhost:8080/John%20Doe, you should see a message stating — Thank you for visiting us today John Doe.
Foe
The artifact created by the build command is most likely the application that you will be running in production.
Since the application.properties are bundled in with the artifact, then these are the properties that will be used when running in production.
Since Spring Boot has a hierarchy to determine which property is used (see Externalized Configuration), this can naturally be overridden with the use of environment variables, which is good practice (see 12Factor app).
java -Dmyapp.welcome.message="Welcome to production" -jar demo-0.0.1-SNAPSHOT.jar
But what if you have a lot of properties?
What if a Developer A added the property myapp.welcome.message
, but didn’t override it in each environment because it’s the same message for all environments? Then Developer B comes along and is testing locally and wants to see what happens if the property is changed to be:
myapp.welcome.message=Is this really working?
It’s very possible that Developer B forgot to revert that change and inadvertently checked it in, which maybe didn’t get caught by a code review. Suddenly, production users are presented with a message stating: “Is this really working?"
Friend
A better approach is to not use application.properties as the default or fallback. Instead, consider one of the below alternatives:
Continue to use application.properties locally but exclude it from the built artifact.
bootJar {
// Do not include application.properties or any of its environment specific equivalents in the built jar
exclude 'application*'
}
OR
processResources {
// Do not include application.properties or any of its environment specific equivalents in the built jar
exclude 'application*'
}
In this scenario, when starting the above application, an error will occur since the injected property does not exist. You then need to go and add that property as an environment variable.
Could not resolve placeholder 'myapp.welcome.message' in value "${myapp.welcome.message}"
To help alleviate the need to wait for the application to fail before you know that you’re missing one or more environment variables is to check if all the environment variables you expect are present as part of the deploy process.
Never use application.properties, instead use something like application-local.properties.
Like the above option, you still need to exclude the file from the built artifact since there is no need to include local properties in a production artifact, even though it will not be used (unless peculiarly production is set to spring.profiles.active=local).
An extra effort with this option is the need to specify spring.profiles.active=local when running locally so that the file is picked up.
Hope you enjoyed this quick look at Spring's application.properties. Let us know your thoughts and questions in the comments.
Further Reading
Opinions expressed by DZone contributors are their own.
Trending
-
File Upload Security and Malware Protection
-
Which Is Better for IoT: Azure RTOS or FreeRTOS?
-
AI Technology Is Drastically Disrupting the Background Screening Industry
-
WireMock: The Ridiculously Easy Way (For Spring Microservices)
Comments