Configuração e profiles
TL;DR
Spring Boot lê propriedades de múltiplas fontes numa hierarquia fixa — args de linha de comando vencem tudo. Profiles recortam configurações por ambiente (
application-{profile}.yml).@ConfigurationPropertiesentrega binding tipado, validado e imutável (records), substituindo@Valueespalhado em todo o código.
O que é
Configuração externalizada (externalized configuration) é o mecanismo pelo qual o Spring Boot injeta valores de fora do artefato — arquivos .yml/.properties, variáveis de ambiente, argumentos de linha de comando — no comportamento da aplicação sem recompilação.
Profiles são rótulos que ativam ou desativam beans e fatias de configuração de acordo com o ambiente em execução (dev, staging, prod, etc.).
@ConfigurationProperties é a annotation que amarra um prefixo de propriedades a uma classe Java (ou record), entregando binding tipado, validação via Bean Validation e suporte a IDE.
Por que importa
- Portabilidade de ambiente: o mesmo JAR roda em dev e prod com configuração diferente, sem alterar o código.
- Segurança operacional: segredos nunca precisam entrar no código-fonte — chegam via variável de ambiente ou cofre (Vault, AWS Secrets Manager).
- Manutenibilidade: propriedades agrupadas em um record anotado com
@ConfigurationPropertiessão fáceis de testar, documentar e validar;@Valueespalhado por dezenas de beans é o oposto disso. - Pergunta frequente em entrevista: a hierarquia de precedência e a diferença entre
@ConfigurationPropertiese@Valueaparecem constantemente em processos seletivos para posições sênior.
Como funciona
Hierarquia/precedência de fontes (args > env > application-{profile} > application > defaults)
Spring Boot avalia propriedades em ordem estrita; a fonte de maior prioridade vence. Simplificando para o dia a dia (da menor para a maior precedência):
- Defaults definidos via
SpringApplication.setDefaultProperties() @PropertySourceem classes@Configuration(não suporta YAML)application.properties/application.ymlno classpathapplication-{profile}.properties/application-{profile}.ymlno classpathapplication.properties/application.ymlexternos (fora do JAR)application-{profile}.properties/application-{profile}.ymlexternos- Variáveis de ambiente do SO (ex.:
SERVER_PORT=9000) - System properties Java (
-Dserver.port=9000) SPRING_APPLICATION_JSON(JSON em variável de ambiente ou system property)- Argumentos de linha de comando (
--server.port=9000) — prioridade máxima em produção
Regra prática
Arquivo de profile externo > arquivo default externo > arquivo de profile no classpath > arquivo default no classpath. Quanto “mais tarde” a fonte é lida, mais ela sobrescreve o que veio antes.
Dentro da categoria “config data” (itens 3–6), arquivos de profile específico sempre sobrepõem o arquivo genérico. Isso significa que application-prod.yml pode sobrescrever qualquer chave definida em application.yml.
Profiles (application-{profile}.yml, @Profile, ativação via env/arg/código)
Um profile é ativado informando seu nome para spring.profiles.active. Múltiplos profiles podem estar ativos ao mesmo tempo.
Ativação via application.yml (padrão de dev local):
spring:
profiles:
active: "dev"Ativação via variável de ambiente (recomendado em produção):
SPRING_PROFILES_ACTIVE=prod java -jar order-service.jarAtivação via argumento de linha de comando:
java -jar order-service.jar --spring.profiles.active=prod,metricsAtivação programática (raramente necessária, útil em testes):
SpringApplication app = new SpringApplication(OrderServiceApplication.class);
app.setAdditionalProfiles("dev", "h2");
app.run(args);Arquivo de configuração específico de profile:
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://db.internal:5432/orders
username: svc_orders
password: ${DB_PASSWORD} # vem de variável de ambiente@Profile em beans — o bean só é registrado no container quando o profile indicado está ativo:
@Configuration
@Profile("dev")
public class DevDataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}Atenção
spring.profiles.activeespring.profiles.defaultnão podem ser definidos dentro de arquivos de profile específicos (ex.: dentro do próprioapplication-prod.yml). Essa restrição evita loops de auto-ativação.
Profile groups permitem ativar vários profiles com um único rótulo lógico:
spring:
profiles:
group:
production:
- "proddb"
- "prodmq"Ativando production, os profiles proddb e prodmq são ativados juntos.
@ConfigurationProperties (binding tipado, record, @Validated, relaxed binding) vs @Value/SpEL
@ConfigurationProperties vincula um prefixo de propriedades a uma classe Java ou record, realizando binding automático de tipos (incluindo listas, mapas e objetos aninhados).
Relaxed binding: o Spring aceita diferentes convenções de nomenclatura para a mesma propriedade. Para um campo maxRetries:
| Formato no arquivo / env | Exemplo |
|---|---|
| kebab-case (recomendado) | order.max-retries |
| camelCase | order.maxRetries |
| underscore | order.max_retries |
| UPPER_SNAKE_CASE (variável de ambiente) | ORDER_MAX_RETRIES |
@Value("${order.maxRetries}") não aplica relaxed binding — precisa do nome exato. @ConfigurationProperties aceita todos os formatos acima.
@Validated aciona a especificação Bean Validation sobre os campos vinculados: se alguma constraint falhar, a aplicação não sobe. Veja Bean Validation (Galho 7) para a spec completa — aqui basta saber que @Validated é a ponte entre Spring e essa especificação.
@Value / SpEL serve para casos pontuais: uma única propriedade, lógica de default inline, ou expressões SpEL complexas. Quando há múltiplas propriedades relacionadas, @ConfigurationProperties é sempre a escolha mais limpa.
Na prática
Exemplo completo com record (Boot 3.x / Java 16+) e YAML:
// src/main/java/com/example/order/config/OrderProperties.java
package com.example.order.config;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties("order")
@Validated
public record OrderProperties(
@NotBlank String serviceUrl,
@Min(1) @Max(10) int maxRetries,
Duration retryDelay
) {}# src/main/resources/application.yml
order:
service-url: "https://api.internal/orders"
max-retries: 3
retry-delay: "PT2S" # ISO-8601: 2 segundos// src/main/java/com/example/order/OrderServiceApplication.java
@SpringBootApplication
@ConfigurationPropertiesScan // registra todos os @ConfigurationProperties do pacote
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}// Uso no serviço — injeção normal por construtor
@Service
public class OrderClient {
private final OrderProperties props;
private final RestClient restClient;
public OrderClient(OrderProperties props, RestClient.Builder builder) {
this.props = props;
this.restClient = builder.baseUrl(props.serviceUrl()).build();
}
}Para override em produção via variável de ambiente:
ORDER_SERVICE_URL=https://api.prod/orders \
ORDER_MAX_RETRIES=5 \
java -jar order-service.jarAssista: ConfigurationProperties explained
Canal: Java Brains | Duração: ~12min | Idioma: EN
Dois ganhos sobre o que esta nota já cobre. O primeiro é a segurança de tipo demonstrada ao vivo: ele troca o valor da porta por
fooe a aplicação simplesmente recusa subir, com a mensagem apontando a propriedade culpada. Um erro de configuração deixa de ser incidente em produção e vira falha de inicialização — que é o momento mais barato possível para descobri-lo. O segundo é o endpoint/actuator/configprops, que lista toda propriedade configurável da aplicação incluindo as centenas que o próprio Spring Boot expõe, cada uma com o valor atualmente em vigor. É a forma de descobrir o que dá para configurar sem caçar na documentação. Trecho de destaque [5:06]: “you essentially get type safety in your configuration… you catch that during application startup time and not some time when the application runs”
Armadilhas
1. Segredo hardcoded em application.yml Colocar senhas, tokens ou chaves de API diretamente no arquivo commitado no repositório expõe credenciais em todo o histórico git. Sempre use referência a variável de ambiente (${DB_PASSWORD}) ou integre com um cofre de segredos.
2. @Value espalhado onde cabia binding tipado Quando um serviço tem cinco ou mais @Value("${order.*}") em campos diferentes, a manutenção se torna caótica: não há validação centralizada, o IDE não autocompleta, e testes unitários precisam mockar cada propriedade manualmente. Agrupe em um @ConfigurationProperties.
3. Relaxed binding mal-entendido: max-retries ↔ maxRetries Desenvolvedores frequentemente esperam que @Value("${order.maxRetries}") leia order.max-retries do YAML por relaxed binding — mas @Value não faz isso. A forma canônica no arquivo deve bater exatamente com o nome na annotation. Relaxed binding é exclusivo de @ConfigurationProperties.
4. @Profile na classe errada com @EnableConfigurationProperties Quando se usa @EnableConfigurationProperties(MyProps.class), colocar @Profile("prod") na classe MyProps não funciona; o profile deve estar na classe @Configuration que registra o bean.
5. @PropertySource com YAML A annotation @PropertySource não suporta arquivos .yml. Para carregar um YAML customizado, use spring.config.import ou o mecanismo padrão de application-{profile}.yml.
Em entrevista
Frase pronta (inglês)
- “Spring Boot resolves configuration through a strict precedence chain — command-line arguments override everything, then environment variables, then profile-specific files, and finally the base
application.yml. This lets you ship one artifact and configure it differently per environment without recompiling.” - “I prefer
@ConfigurationPropertiesover scattered@Valuefields because it gives me a single, validated, type-safe object that’s easy to test and document. I annotate it with@Validatedto catch misconfigured deployments at startup, not at runtime.” - “Profiles in Spring Boot are just labels:
application-prod.ymlis loaded automatically when theprodprofile is active, and@Profile("prod")gates beans to that context. In CI/CD, I activate profiles through theSPRING_PROFILES_ACTIVEenvironment variable so the configuration stays out of the artifact.”
Vocabulário
| Termo PT | Termo EN |
|---|---|
| Configuração externalizada | Externalized configuration |
| Fonte de propriedades | Property source |
| Hierarquia de precedência | Precedence hierarchy / property source order |
| Binding tipado | Type-safe binding |
| Vinculação relaxada | Relaxed binding |
| Perfil ativo | Active profile |
| Grupo de profiles | Profile group |
| Propriedade de ambiente | Environment variable |
| Argumento de linha de comando | Command-line argument |
| Validação na inicialização | Startup validation / fail-fast validation |
Veja também
- Qualificação de beans —
@Profilena perspectiva de qualificação de beans - Bean Validation —
@Validatedaciona a spec Bean Validation do Galho 7; esta nota não re-explica a spec, apenas a consome - Spring Core e Boot (MOC do galho)
- Trilha Java
- @ConfigurationProperties (verbete)
- @Value (verbete)