Configuration Management
Configuration management serves as the bridge between development and production—one codebase, multiple configurations, and switching between environments requires just a single line of parameters.
1. What You'll Learn
- Profile Mechanism:
application-dev.yml/application-prod.ymlMulti-Environment Switching - Comparison of Type-Safe Binding
@ConfigurationPropertiesand Injection@Value - Configuration priority order: command-line arguments > environment variables > configuration files > default values
- Nested Configuration and Binding to List/Map Types
- Best Practices for Externalizing OrderFlow Data Source and Third-Party API Key Configurations
2. A True Story of an Operations Engineer
(1) Pain Point: Configurations are scattered all over the place
Bob is an operations engineer at OrderFlow, and every deployment feels like an "archaeological dig": database passwords are hard-coded into the code, and the configurations for the test and production environments are mixed together in a single file. Someone changed the production database password but forgot to update the code, causing the system to go down for two hours. When Charlie pressed him about the SLA, Bob could only explain, with a sigh, that "configuration management is a mess."
(2) Solutions for Spring Boot Profiles
Spring Boot uses the Profile mechanism to separate configurations for multiple environments:
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/orderflow_dev
username: dev_user
password: dev_pass
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db.internal:3306/orderflow
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
(3) Revenue
After Bob refactored the code using Profile and environment variables, the development environment now uses dev and the production environment uses prod. Sensitive information no longer appears in the code repository, and switching deployments requires only --spring.profiles.active=prod, reducing downtime caused by configuration errors to zero.
3. Profile: Multi-Environment Configuration
(1) Profile File Naming Conventions
Spring Boot loads profile configurations according to the application-{profile}.yml naming convention:
src/main/resources/
├── application.yml # Common config (shared)
├── application-dev.yml # Dev profile
├── application-prod.yml # Prod profile
└── application-test.yml # Test profile
graph TD
A["application.yml<br/>Common Config"] --> B["application-dev.yml<br/>Dev Overrides"]
A --> C["application-prod.yml<br/>Prod Overrides"]
A --> D["application-test.yml<br/>Test Overrides"]
B --> E["Merged Config<br/>Profile=dev"]
C --> F["Merged Config<br/>Profile=prod"]
| Activation Method | Command | Priority |
|---|---|---|
| Configuration File | spring.profiles.active=dev in application.yml |
Minimum |
| Environment Variable | SPRING_PROFILES_ACTIVE=dev |
Chinese |
| Command-line argument | --spring.profiles.active=dev |
Maximum |
(1) ▶ Example: Profile
# application.yml (shared)
spring:
application:
name: orderflow-service
profiles:
active: dev
server:
port: 8080
Output:
Configuration applied successfully
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:orderflow_dev
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
logging:
level:
com.orderflow: DEBUG
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://${DB_HOST:localhost}:3306/orderflow
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
show-sql: false
logging:
level:
com.orderflow: WARN
4. Comparison of @Value and @ConfigurationProperties
(1) Two Injection Methods
(1) ▶ Example: @Value Injection
@RestController
public class OrderController {
@Value("${orderflow.max-items-per-order:100}")
private int maxItemsPerOrder;
@Value("${orderflow.default-currency:USD}")
private String defaultCurrency;
@GetMapping("/api/config/check")
public Map<String, Object> checkConfig() {
return Map.of(
"maxItemsPerOrder", maxItemsPerOrder,
"defaultCurrency", defaultCurrency
);
}
}
Output:
// Execution Successful
(2) ▶ Example: Type-safe binding with @ConfigurationProperties
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
int maxItemsPerOrder,
String defaultCurrency,
Duration orderTimeout,
ShippingConfig shipping
) {
public record ShippingConfig(
boolean freeShippingEnabled,
BigDecimal freeShippingThreshold
) {}
}
// Enable in main class or config class
@EnableConfigurationProperties(OrderFlowProperties.class)
Output:
// Execution Successful
| Dimension | @Value |
@ConfigurationProperties |
|---|---|---|
| Type Safety | Weak (primarily String) | Strong (automatic type conversion) |
| Nested objects | Not supported | Supported |
| Collection Binding | Not Supported | Supports List/Map |
| Verification | None | In conjunction with @Validated |
| IDE Support | No hints | Auto-completion (metadata) |
| Use Cases | Small Number of Simple Values | Structured Business Configuration |
(3) ▶ Example: YAML and ConfigurationProperties Mappings
orderflow:
max-items-per-order: 50
default-currency: USD
order-timeout: 30m
shipping:
free-shipping-enabled: true
free-shipping-threshold: 49.99
Output:
The configuration has taken effect.
// Access example
@Component
public class OrderService {
private final OrderFlowProperties props;
public OrderService(OrderFlowProperties props) {
this.props = props;
}
public boolean isFreeShipping(BigDecimal orderTotal) {
return props.shipping().freeShippingEnabled()
&& orderTotal.compareTo(props.shipping().freeShippingThreshold()) >= 0;
}
}
5. Configuration Priority Hierarchy
(1) Priority from highest to lowest
graph TD
A["1. Command Line Args<br/>--server.port=9090"] --> B["2. JNDI Attributes"]
B --> C["3. Java System Properties<br/>-Dserver.port=9090"]
C --> D["4. OS Environment Variables<br/>SERVER_PORT=9090"]
D --> E["5. application-{profile}.yml<br/>Profile-specific"]
E --> F["6. application.yml<br/>Default config"]
F --> G["7. @Default Values<br/>In code annotations"]
| Priority | Source | Example |
|---|---|---|
| 1 (Highest) | Command-line arguments | --server.port=9090 |
| 2 | JNDI Properties | java:comp/env/... |
| 3 | JVM System Properties | -Dserver.port=9090 |
| 4 | OS Environment Variables | SERVER_PORT=9090 |
| 5 | Profile | application-prod.yml |
| 6 | Default Configuration File | application.yml |
| 7 (minimum) | Default value | @Value("${x:default}") |
6. Nested Configuration and Collection Binding
(1) Binding Lists and Maps
(1) ▶ Example: List and Map Configuration
orderflow:
supported-currencies:
- USD
- EUR
- GBP
payment-gateways:
stripe:
api-key: ${STRIPE_API_KEY}
webhook-secret: ${STRIPE_WEBHOOK_SECRET}
paypal:
client-id: ${PAYPAL_CLIENT_ID}
secret: ${PAYPAL_SECRET}
Output:
CI/CD pipeline configuration has been loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
List<String> supportedCurrencies,
Map<String, GatewayConfig> paymentGateways
) {
public record GatewayConfig(
String apiKey,
String webhookSecret,
String clientId,
String secret
) {}
}
7. Comprehensive Example: The Complete OrderFlow Configuration System
// OrderFlowProperties.java
package com.orderflow.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.List;
import java.util.Map;
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
int maxItemsPerOrder,
String defaultCurrency,
Duration orderTimeout,
ShippingConfig shipping,
List<String> supportedCurrencies,
Map<String, GatewayConfig> paymentGateways
) {
public record ShippingConfig(
boolean freeShippingEnabled,
BigDecimal freeShippingThreshold
) {}
public record GatewayConfig(
String apiKey,
String webhookSecret,
String clientId,
String secret
) {}
}
// AppConfig.java
package com.orderflow.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(OrderFlowProperties.class)
public class AppConfig {}
# application.yml
spring:
application:
name: orderflow-service
profiles:
active: dev
orderflow:
max-items-per-order: 50
default-currency: USD
order-timeout: 30m
supported-currencies:
- USD
- EUR
- GBP
shipping:
free-shipping-enabled: true
free-shipping-threshold: 49.99
payment-gateways:
stripe:
api-key: ${STRIPE_API_KEY:dev-key}
webhook-secret: ${STRIPE_WEBHOOK_SECRET:dev-secret}
❓ FAQ
.gitignore; 3) Use K8s Secrets or Vault to manage secrets in production environments.orderflow.supported-currencies[0]=USD, orderflow.supported-currencies[1]=EUR. List indices start at 0.record as a ConfigurationProperties?record is immutable and is suitable for read-only configurations. Spring Boot 3.x supports record binding. However, it cannot be used with @Validated for JSR-380 validation (since record lacks a no-argument constructor), so a class must be used instead.📖 Summary
- The Profile mechanism enables configuration separation across multiple environments;
application-{profile}.ymloverrides the default configuration @ConfigurationPropertiesType-safe binding is superior to@Valueand supports nesting, sets, and validation- Configuration priority: Command line > Environment variables > Profile file > Default file > Code defaults
- Use the
${ENV_VAR}placeholder for sensitive information; do not hard-code it into the configuration file - Spring Boot 3.x supports using
recordasConfigurationProperties
📝 Exercises
-
Basic Exercise (Difficulty ⭐): Configure two profiles for OrderFlow—one for dev and one for prod. The dev profile uses the H2 in-memory database, while the prod profile uses MySQL. Switch between them using command-line arguments.
-
Advanced Problem (Difficulty ⭐⭐): Use
@ConfigurationPropertiesto createPaymentGatewayProperties, which includes API key configurations for Stripe and PayPal; inject the key values via environment variables. -
Challenge (Difficulty: ⭐⭐⭐): Implement a custom
PropertySourceto load configuration from a remote configuration center (you may use a mocked HTTP endpoint), and consider the design intent behind the Spring BootEnvironmentabstraction.



