Gerenciamento de Configuração
O gerenciamento de configuração serve como ponte entre desenvolvimento e produção—uma base de código, múltiplas configurações, e a alternância entre ambientes requer apenas uma linha de parâmetros.
1. O Que Você Vai Aprender
- Mecanismo de Profile:
application-dev.yml/application-prod.ymlAlternância de Múltiplos Ambientes - Comparação do Binding Tipo-Seguro
@ConfigurationPropertiese Injeção@Value - Ordem de prioridade de configuração: argumentos de linha de comando > variáveis de ambiente > arquivos de configuração > valores padrão
- Configuração Aninhada e Binding para Tipos List/Map
- Melhores Práticas para Externalizar Configurações de Fonte de Dados e Chaves de API de Terceiros do OrderFlow
2. Uma História Real de um Engenheiro de Operações
(1) Ponto de Dor: Configurações espalhadas por todo lado
Bob é um engenheiro de operações no OrderFlow, e toda implantação parece uma "escavação arqueológica": senhas de banco de dados estão hard-coded no código, e as configurações dos ambientes de teste e produção estão misturadas em um único arquivo. Alguém alterou a senha do banco de dados de produção mas esqueceu de atualizar o código, causando queda do sistema por duas horas. Quando Charlie cobrou dele sobre o SLA, Bob só pôde explicar, com um suspiro, que "o gerenciamento de configuração é uma bagunça."
(2) Soluções com Spring Boot Profiles
O Spring Boot usa o mecanismo de Profile para separar configurações de múltiplos ambientes:
# 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) Resultado
Depois que Bob refatorou o código usando Profile e variáveis de ambiente, o ambiente de desenvolvimento agora usa dev e o ambiente de produção usa prod. Informações sensíveis não aparecem mais no repositório de código, e a alternância de implantações requer apenas --spring.profiles.active=prod, reduzindo o tempo de inatividade causado por erros de configuração a zero.
3. Profile: Configuração de Múltiplos Ambientes
(1) Convenções de Nomenclatura de Arquivo de Profile
O Spring Boot carrega configurações de perfil de acordo com a convenção de nomenclatura application-{profile}.yml:
src/main/resources/
├── application.yml # Configuração comum (compartilhada)
├── application-dev.yml # Profile de dev
├── application-prod.yml # Profile de produção
└── application-test.yml # Profile de teste
graph TD
A["application.yml<br/>Configuração Comum"] --> B["application-dev.yml<br/>Substituições de Dev"]
A --> C["application-prod.yml<br/>Substituições de Prod"]
A --> D["application-test.yml<br/>Substituições de Test"]
B --> E["Configuração Mesclada<br/>Profile=dev"]
C --> F["Configuração Mesclada<br/>Profile=prod"]
| Método de Ativação | Comando | Prioridade |
|---|---|---|
| Arquivo de Configuração | spring.profiles.active=dev em application.yml |
Mínima |
| Variável de Ambiente | SPRING_PROFILES_ACTIVE=dev |
Média |
| Argumento de linha de comando | --spring.profiles.active=dev |
Máxima |
(1) ▶ Exemplo: Profile
# application.yml (compartilhado)
spring:
application:
name: orderflow-service
profiles:
active: dev
server:
port: 8080
Saída:
Configuração aplicada com sucesso
# 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. Comparação de @Value e @ConfigurationProperties
(1) Dois Métodos de Injeção
(1) ▶ Exemplo: Injeção com @Value
@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
);
}
}
Saída:
// Execução bem-sucedida
(2) ▶ Exemplo: Binding tipo-seguro com @ConfigurationProperties
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
int maxItemsPerOrder,
String defaultCurrency,
Duration orderTimeout,
ShippingConfig shipping
) {
public record ShippingConfig(
boolean freeShippingEnabled,
BigDecimal freeShippingThreshold
) {}
}
// Ativar na classe principal ou classe de configuração
@EnableConfigurationProperties(OrderFlowProperties.class)
Saída:
// Execução bem-sucedida
| Dimensão | @Value |
@ConfigurationProperties |
|---|---|---|
| Segurança de Tipo | Fraca (primariamente String) | Forte (conversão automática de tipo) |
| Objetos aninhados | Não suportado | Suportado |
| Binding de Coleção | Não Suportado | Suporta List/Map |
| Verificação | Nenhuma | Em conjunto com @Validated |
| Suporte IDE | Sem sugestões | Auto-completar (metadados) |
| Casos de Uso | Pequena Quantidade de Valores Simples | Configuração de Negócio Estruturada |
(3) ▶ Exemplo: Mapeamentos YAML e ConfigurationProperties
orderflow:
max-items-per-order: 50
default-currency: USD
order-timeout: 30m
shipping:
free-shipping-enabled: true
free-shipping-threshold: 49.99
Saída:
A configuração entrou em vigor.
// Exemplo de acesso
@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. Hierarquia de Prioridade de Configuração
(1) Prioridade da mais alta para a mais baixa
graph TD
A["1. Argumentos de Linha de Comando<br/>--server.port=9090"] --> B["2. Atributos JNDI"]
B --> C["3. Propriedades do Sistema Java<br/>-Dserver.port=9090"]
C --> D["4. Variáveis de Ambiente do SO<br/>SERVER_PORT=9090"]
D --> E["5. application-{profile}.yml<br/>Específico do Profile"]
E --> F["6. application.yml<br/>Configuração padrão"]
F --> G["7. @Default Values<br/>Em anotações de código"]
| Prioridade | Origem | Exemplo |
|---|---|---|
| 1 (Mais Alta) | Argumentos de linha de comando | --server.port=9090 |
| 2 | Propriedades JNDI | java:comp/env/... |
| 3 | Propriedades do Sistema JVM | -Dserver.port=9090 |
| 4 | Variáveis de Ambiente do SO | SERVER_PORT=9090 |
| 5 | Profile | application-prod.yml |
| 6 | Arquivo de Configuração Padrão | application.yml |
| 7 (mínima) | Valor padrão | @Value("${x:default}") |
6. Configuração Aninhada e Binding de Coleção
(1) Binding de Listas e Maps
(1) ▶ Exemplo: Configuração de List e Map
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}
Saída:
Configuração do pipeline CI/CD foi carregada
Status do pipeline: passed
Testes: 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. Exemplo Abrangente: O Sistema de Configuração Completo do OrderFlow
// 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}
❓ Perguntas Frequentes
${ENV_VAR} em arquivos de configuração para referenciar variáveis de ambiente; 2) Exclua arquivos de configuração sensíveis no .gitignore; 3) Use K8s Secrets ou Vault para gerenciar secrets em ambientes de produção.orderflow.supported-currencies[0]=USD, orderflow.supported-currencies[1]=EUR. Índices de lista começam em 0.record como ConfigurationProperties?record é imutável e é adequado para configurações somente leitura. Spring Boot 3.x suporta binding de record. No entanto, ele não pode ser usado com @Validated para validação JSR-380 (já que record não tem construtor sem argumentos), então uma classe deve ser usada em vez disso.📖 Resumo
- O mecanismo de Profile permite separação de configuração entre múltiplos ambientes;
application-{profile}.ymlsobrescreve a configuração padrão @ConfigurationPropertiesBinding tipo-seguro é superior ao@Valuee suporta aninhamento, conjuntos e validação- Prioridade de configuração: Linha de comando > Variáveis de ambiente > Arquivo de Profile > Arquivo padrão > Padrões de código
- Use o placeholder
${ENV_VAR}para informações sensíveis; não faça hard-code no arquivo de configuração - Spring Boot 3.x suporta usar
recordcomoConfigurationProperties
📝 Exercícios
-
Exercício Básico (Dificuldade ⭐): Configure dois profiles para o OrderFlow—um para dev e um para prod. O profile de dev usa o banco de dados em memória H2, enquanto o profile de prod usa MySQL. Alterne entre eles usando argumentos de linha de comando.
-
Problema Avançado (Dificuldade ⭐⭐): Use
@ConfigurationPropertiespara criarPaymentGatewayProperties, que inclui configurações de chave de API para Stripe e PayPal; injete os valores das chaves via variáveis de ambiente. -
Desafio (Dificuldade: ⭐⭐⭐): Implemente um
PropertySourcepersonalizado para carregar configuração de um centro de configuração remoto (você pode usar um endpoint HTTP simulado), e considere a intenção de design por trás da abstraçãoEnvironmentdo Spring Boot.



