🌱 Spring Boot Q37 / 69

How does Spring Boot manage environment properties?

AI-Powered Answer ✓ Answered

Spring Boot provides a robust and flexible mechanism for managing environment properties, allowing applications to externalize configuration. This means you can run the same application code in different environments (development, test, production) by simply changing the configuration without repackaging the application. This guide explores the various ways Spring Boot manages and prioritizes these properties.

Overview of Externalized Configuration

Spring Boot applications are designed for externalized configuration, enabling you to use the same compiled code across multiple environments. You can provide configuration using property files, YAML files, environment variables, command-line arguments, and more. The framework's ConfigurableEnvironment plays a central role, abstracting the underlying property sources and providing a consistent API to access properties.

Property Sources and Order of Precedence

Spring Boot loads properties from various sources and consolidates them into a unified Environment. When a property is defined in multiple sources, Spring Boot applies a specific order of precedence, with higher-priority sources overriding lower-priority ones. This allows for fine-grained control over configuration values.

  • Devtools global settings properties (when active).
  • @TestPropertySource annotations on your tests.
  • Properties attribute on your tests (e.g., @SpringBootTest(properties = "a=b")).
  • Command-line arguments (e.g., --server.port=8081).
  • Properties from SPRING_APPLICATION_JSON (inline JSON in an environment variable).
  • ServletConfig init parameters.
  • ServletContext init parameters.
  • JNDI attributes from java:comp/env.
  • JVM system properties (System.getProperties()).
  • Operating system environment variables.
  • RandomValuePropertySource for random.* properties.
  • Application-specific properties outside your packaged JAR (e.g., application-{profile}.properties, application.properties in the current directory).
  • Application-specific properties inside your packaged JAR (e.g., application-{profile}.properties, application.properties in the classpath).
  • @PropertySource annotations on your @Configuration classes.
  • Default properties (specified by SpringApplication.setDefaultProperties).

Common Configuration Files

The most common way to define properties is through application.properties or application.yml files, typically located in the src/main/resources directory. YAML files offer a more human-readable and structured format.

Example application.properties:

properties
server.port=8080
spring.application.name=my-spring-app
my.custom.property=Hello from properties

Example application.yml:

yaml
server:
  port: 8080
spring:
  application:
    name: my-spring-app
my:
  custom:
    property: Hello from YAML

Profile-Specific Properties

Spring Boot supports profile-specific properties, allowing you to define different configurations for different environments (e.g., dev, test, prod). You can create files like application-dev.properties or application-prod.yml. The active profile can be set using spring.profiles.active property.

Example application-dev.properties:

properties
server.port=8081
my.custom.property=Hello from Development

To activate this profile, you can use a command-line argument: --spring.profiles.active=dev or an environment variable SPRING_PROFILES_ACTIVE=dev.

Command-Line Arguments and Environment Variables

Command-line arguments (prefixed with --) and operating system environment variables provide a simple way to override properties at runtime. These have a higher precedence than properties defined in application.properties/yml files.

Example using command-line arguments to override the server port:

bash
java -jar my-spring-app.jar --server.port=9000

Spring Boot also supports relaxed binding for environment variables, meaning SERVER_PORT, SERVER_PORT, or server_port can all map to server.port.

Accessing Properties in Your Application

Spring Boot provides several ways to access configured properties within your application code.

1. Using the @Value annotation for individual properties:

java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    @Value("${my.custom.property:Default Value}")
    private String customProperty;

    public void doSomething() {
        System.out.println("Custom Property: " + customProperty);
    }
}

2. Using the Environment object to programmatically access properties:

java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class MyAnotherService {

    @Autowired
    private Environment env;

    public void doAnotherThing() {
        String appName = env.getProperty("spring.application.name");
        System.out.println("Application Name: " + appName);
    }
}

3. Using @ConfigurationProperties for type-safe externalized configuration:

This approach binds an entire branch of properties to a Java object, providing strong typing, validation, and documentation.

java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "app.settings")
public class AppSettings {

    private String name;
    private int maxUsers;
    private String apiKey;

    // Getters and Setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMaxUsers() {
        return maxUsers;
    }

    public void setMaxUsers(int maxUsers) {
        this.maxUsers = maxUsers;
    }

    public String getApiKey() {
        return apiKey;
    }

    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }
}

Corresponding application.yml or application.properties:

yaml
app:
  settings:
    name: My Awesome App
    max-users: 1000
    api-key: some-secret-key-123

Conclusion

Spring Boot's property management system is highly flexible and powerful, designed to make externalized configuration straightforward. By understanding the various property sources and their order of precedence, developers can effectively manage application settings across different environments, enhancing portability and maintainability. Whether using simple .properties files, structured YAML, or advanced @ConfigurationProperties, Spring Boot offers the right tool for every configuration need.