Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Spring

Configuration files

What is a configuration file, and how is it different from writing values in the code?

A configuration file is a text file kept separate from the code. In Spring Boot it is named application.properties, and you write "name=value" lines in it (shop.name=kim-shop). If you write values that differ between environments, such as a port number or a connection address, directly in the code, you have to change the code and compile it again every time a value changes. So you keep the value in this file, and the code writes only the name. If you write an @Value("${name}") line above a field that needs a value, then when Spring creates the object, it looks for the value of that name in the configuration file and puts it in the field. If you write a default value after a : in the form ${name:default}, that value is used when the settings have no such name. In this lab you change or delete the shop.name line of the configuration file, and add or remove a default value on @Value, and run the program with the java command, to see what value comes into the name field and whether the program starts properly.

Checked against real execution · Compiled the source for each of the six combinations on Spring Boot 4.1.1, ran it as a child java process, and checked against the standard output, exit code, and exception observed from outside the process

Concepts in this lab

application.properties
application.properties is the name of the configuration file that Spring Boot finds and reads automatically when it starts. It is not Java code but a text file that collects "name=value" lines (for example shop.name=kim-shop), and a line that starts with # is read as a note, not as a setting. Spring Boot looks for this file at the root of the class path (usually src/main/resources), in /config of the class path, in the folder where the program was run, and in the config folder of that folder, and the values it reads go into the Spring Environment as a property source (PropertySource). You can also write the same content as application.yaml in the YAML format. To change a value, you change only this file without changing the code, so it is used as the place for values that differ between environments.
@Value
@Value is an annotation that marks a field or a constructor parameter so that Spring puts a value in it when it creates the object. If you write the name of a setting inside ${ } as in @Value("${shop.name}"), Spring finds the value of that name in the settings and puts it in. We do not have to write code that puts a value in that field. In Spring Boot, if the settings do not have that name and no default value is written, the object cannot be created and the application stops while starting. To be ready for a missing name, write a default value after a : as in ${shop.name:no-name}.
${...} placeholder
${name} is a piece of text that marks "the value of that name in the settings goes here". Before Spring uses the value, it finds the name in the settings and replaces this part with the value, and it can be used not only in @Value("${name}") but also inside a value in application.properties (for example app.description=${app.name} is an app). The value written after a : as in ${name:default} is used only when the settings do not have that name, and it is not used when the name exists. Spring Boot registers by default a configurer (PropertySourcesPlaceholderConfigurer) so that startup fails if this part cannot be resolved. If you use only Spring Framework and do not put in this configurer, the unresolved ${name} text goes in as the value as it is.
Externalized configuration and profiles
Externalized configuration means supplying setting values such as a DB address through configuration files, environment variables, command-line arguments, and so on, without putting them in the code. It lets you run the same build artifact with different settings in different environments. A profile is a feature that keeps groups of settings separated by environment, such as development and production, and lets you select one at run time.

Try these

Running with the default settings

  1. When you run the App class with the java command on the computer, Java calls the main method of the App class. The first line of the main method, SpringApplication.run(App.class, args), starts Spring Boot.
  2. As it starts, Spring Boot finds and reads the file application.properties in the place where the class files are. This file is not Java code but a text file that collects "name=value" lines. It reads the line shop.name=kim-shop and records one pair, shop.name = kim-shop, in Spring's settings list.
  3. Next, Spring scans the classes starting from the package where the App class is, finds the ShopInfo class with @Component, and starts to create its object. The code we wrote has no line new ShopInfo(). Spring creates the object inside the SpringApplication.run line of the main method.
  4. While creating the object, Spring reads the @Value("${shop.name}") line above the name field. What is inside ${ } means "go and find the value of this name in the settings list". Looking in the settings list for the name shop.name, Spring finds the value kim-shop, so it puts that value into the name field. The code we wrote has no line that puts a value in name either.
  5. The SpringApplication.run line ends and the main method goes to the next line. The ctx.getBean line takes out the ShopInfo object that Spring made and kept, and puts it in info. The name of this object already holds the value kim-shop.
  6. The System.out.println(info.name) line prints the text held in name to the screen. One line, kim-shop, is printed to the screen.
  7. The main method ends. This project has no web server waiting for requests, so the java process also ends as it is (exit code 0).

Result of this run

Code

# application.properties
# Setting: a value written outside the code in the form name=value
shop.name=kim-shop

@Component
class ShopInfo {
    // Receive: find the value of shop.name in the settings and put it in name
    @Value("${shop.name}")
    String name;
}

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        // Start Spring. ctx is the place that keeps the objects Spring made
        ApplicationContext ctx = SpringApplication.run(App.class, args);
        ShopInfo info = ctx.getBean(ShopInfo.class);
        System.out.println(info.name);
    }
}

Assumptions of this model

This is the result of running Spring Boot 4.1.1 (Spring Framework 7.0.9) on JDK 21.0.12.1. All six combinations were checked by compiling a source with the same structure as the code on the screen (ShopInfo and App in the package app, and application.properties in the same folder as the class files), running app.App from its main method as a new process with the java command, and comparing the results. What was checked is the three items of the result table. The value that came into name was decided from the text the process printed to the standard output, whether the startup succeeded from the exit code (0 and 1) and the standard output, and the error from the name and message of the exception on the standard error. In the combinations where the configuration file is deleted, only the shop.name line and the note line right above it were removed from the file, and the # application.properties line at the top was left. The facts that the step sentences rely on were also checked by execution. In the combinations with a configuration file, Spring reads application.properties on the class path as a source of settings (Config resource class path resource [application.properties]) and the shop.name value in it is in the Spring Environment. When SpringApplication.run ends, the ShopInfo object has already been made and the name field holds the value. Our source has no new ShopInfo() and no line that puts a value in name. When there is no shop.name line and no default value, an exception (BeanCreationException, whose cause is a PlaceholderResolutionException with Could not resolve placeholder 'shop.name' in value "${shop.name}") comes out of the SpringApplication.run line, main cannot go on to the next line and ends with exit code 1, and nothing is printed to the standard output. When only application.properties is changed from kim-shop to lee-shop and the program is run again from the same compile result (the hashes of the ShopInfo.class file and the App.class file are the same), lee-shop comes out without compiling. In the combination where the shop.name line is deleted and a default value is written, the file has no name=value line at all, and it was observed that application.properties does not appear in the list of setting sources of Spring. The step sentence says only as far as "the settings list does not have the name shop.name". For the class path, only the 21 jars that spring-boot-starter brings in were given, not the whole library folder (the same list as the Spring Boot Fundamentals lab, with no web library), and the working folder of the child process was an empty temporary folder (because Spring Boot also reads application.properties and the config folder in the working folder). The environment variables starting with SPRING_ and SHOP_ were removed from the child process. What the documentation defines comes from the section Externalized Configuration of the Spring Boot documentation (that when it starts, it finds and reads application.properties at the root of the class path, in the /config package of the class path, in the current folder, and in the config folder of the current folder; that settings are kept outside the code so that the same code can be used in different environments; and that in ${name:default}, what follows the : is the default value) and the section Using @Value of the Spring Framework documentation (that @Value("${...}") injects an external setting value; the default value syntax; that Spring Boot registers by default the PropertySourcesPlaceholderConfigurer that reads the values of application.properties; and that when this configurer is present, initialization fails if a ${} placeholder cannot be resolved). The documentation also says that if you use only Spring Framework and do not put this configurer in, the unresolved ${shop.name} text goes in as the value as it is, but this lab was run only on Spring Boot. That BeanCreationException and PlaceholderResolutionException come out when the value is missing is not defined by the documentation but is a behavior observed on this version. The code on the screen leaves out the package and import lines and assumes that ShopInfo and App are in the same package. In reality the two classes are in separate files, and application.properties is usually put in src/main/resources and copied next to the class files by the build (here it was put in that folder directly). What this lab does not cover is application.yml, the precedence when the same name is in several places, changing values with environment variables and run arguments, files for each profile, and @ConfigurationProperties. The precedence is covered in the in-depth lab "Configuration precedence", and Spring Boot making beans by itself after looking at the settings is covered in the in-depth lab "Spring Boot auto-configuration".

Previous lab: Controllers · Next lab: JDBC

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these