Who this post is for
If you are just getting started with Spring Boot 2, then this post is for you.
As a prerequisite, you have installed Java, Maven, and an IDE like IntelliJ, and you followed along with the Build A Next-Level RESTful Web Service with Spring Boot 2 post. You currently have a running RESTful web service.
Let’s get started
Let’s use the greeting application from the Building a next-level RESTful web service article to add and use a property.
The first thing you will notice is that in the /src/main/resources
directory of this application, there is an application.properties
file. This file is empty right now. This file was generated by Spring Initializr when we created the application. Remember that I mentioned that the Spring team recommends starting every Spring Boot application with Spring Initializr.
What is this file? application.properties
is one of the default “property sources” meaning it is one place that Spring Boot is going to look for properties when the application starts up. Actually, Spring Boot looks for a file named application.properties
in several places. You can read about that in the Spring Boot documentation.
Add a property
You can store properties for your Spring Boot 2 applications and services in the application.properties
file in a key-value format.
Open up application.properties
and add the line:
defaultGreeting=Hello
Once that’s done, you can use the @Value
annotation anywhere within your application to refer to this property. The @Value
annotation can refer to property variables with placeholders, which use the ${myVariableName}
syntax. You can read more about placeholders in the Spring Boot documentation.
Use the property
Open GreetingController.java
(found somewhere in /src/main/java/
), and let’s now change the template variable from a static variable to a member variable, and annotate it with @Value("${defaultGreeting}")
. I also changed the variable name from template
to greeting
, because “template” isn’t accurate anymore.
The result is this:
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/greeting")
public class GreetingController {
private final AtomicLong counter = new AtomicLong();
@Value("${defaultGreeting}")
private String greeting;
@GetMapping
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return customizeGreeting(name);
}
@PutMapping
public ResponseEntity<Greeting> update(String greeting) {
this.greeting = greeting;
return ResponseEntity.ok(customizeGreeting("World"));
}
private Greeting customizeGreeting(String name) {
return new Greeting(counter.incrementAndGet(), greeting + ", " + name);
}
}
Be sure to build (mvn package
), run (java -jar target/yourjar.jar
), and test this before continuing, just like you did before using curl or Postman. Remember that you will send a GET request to http://localhost:8080/greeting.
Also try updating the value of defaultGreeting
in application.properties
. You will notice that when you change it while the application is running, nothing happens. You have to stop the application, rebuild it, and rerun it in order for the application to pick up the change.
Properties from Arguments
You currently have a defaultGreeting
property in application.properties
and you know how to change it.
The rebuild and rerun part of changing a property is fine for some things, but it may not quite be what you want.
What if you could set this property any time you start the application, without changing the application.properties file and rebuilding?
Luckily, you can. Currently, you run the application like this:
java -jar target/greeting-0.0.1-SNAPSHOT.jar
(Note that you may have named your application something else besides “greeting” so that would appear in the jar file name instead.)
You can actually pass properties, as arguments, to that run command. Try this, and see what happens:
java -DdefaultGreeting="Hey" -jar target/greeting-0.0.1-SNAPSHOT.jar
If you test that, you’ll notice that the default greeting changed to “Hey” as expected.
Environment variables
One of the main reasons to use properties is so that your application can run on different machines, but be customized in some ways for the machine it’s running on. Maybe you distinguish between a dev or test machine and a production machine. Or maybe the difference is simply about who is running the application.
In this greeting application, what if we could use the username from the environment to set the default person that the greeting is for?
This is actually rather easy with Spring Boot! Assuming you are using BASH shell, you should have a $USER
environment variable. Open a terminal and try typing echo $USER
and you should see your username. If you do not have a BASH shell on your machine, go find out how to set an environment variable named USER
for your OS before proceeding, and set it to your username.
Update the code to use an environment variable property
So we know that we want to refer to an environment variable named $USER
. Can you think of how you might change the code to do that? (Hint: using the @Value
annotation.)
As silly as it sounds, you can directly refer to environment variables in @Value
annotations in Spring Boot, because it automatically loads them. Environment variables are a default property source that the application populates when it loads up.
So you essentially just add @Value("${USER}")
. Go ahead and add a member of the class named user that is a String.
Now, you’ll want to make it so that by default the name variable is set to this value. You may think that we can just set the defaultValue
attribute of the @RequestParam
to our new user variable, but that won’t be allowed because it requires the use of a constant. So, instead, let’s just remove that. The next thing that we run into is that, by default, query parameters are required, but you can set a required = false
attribute, so I’m going to do that. Now, I’m going to go ahead and just check if name is null
when we receive it, and in that case set it to the value of user. My final code looks like this:
@RestController
@RequestMapping("/greeting")
public class GreetingController {
private final AtomicLong counter = new AtomicLong();
@Value("${defaultGreeting}")
private String greeting;
@Value("${USER}")
private String user = "World";
@GetMapping
public Greeting greeting(@RequestParam(value = "name", required = false) String name) {
if(name == null) {
name = user;
}
return customizeGreeting(name);
}
@PutMapping
public ResponseEntity<Greeting> update(String greeting) {
this.greeting = greeting;
return ResponseEntity.ok(customizeGreeting("World"));
}
private Greeting customizeGreeting(String name) {
return new Greeting(counter.incrementAndGet(), greeting + ", " + name);
}
}
With those changes in place, I rebuild and rerun the application, and now by default the response to my GET request is, “Hello, scottshi” because “scottshi” happens to be the username I chose on this computer. When you run it, you should see your username instead.
What you learned
In this post, you learned how to provide configuration (properties) to a Spring Boot application via:
environment variables
command-line arguments
application.properties
. . . and consume them with the @Value
annotation.
In a future post, I will cover more ways to consume properties.
Where to learn more
If you are ready to learn more, right now, check out the Spring Boot reference manual where you can learn:
additional default property sources
the order of evaluation that Spring Boot follows to determine which properties win
Top comments (0)