Что такое profiles in Spring
Один и тот же скомпилированный JAR-архив приложения должен работать:
🟢 Junior Level
Profiles (профили) в Spring Framework — это встроенный механизм сегментации конфигурации приложения, позволяющий регистрировать разные бины и применять различные свойства (application.properties / application.yml) в зависимости от текущего окружения запуска (например: local, dev, stage, prod).
Зачем нужны профили
Один и тот же скомпилированный JAR-архив приложения должен работать:
- На машине разработчика (
local): локальная база данных H2 или Docker-контейнер, включен подробный логDEBUG. - В тестовом контуре (
test): моки внешних платежных шлюзов, изолированная база данных. - В боевом окружении (
prod): кластер PostgreSQL с пулом HikariCP, защищенные SSL-сертификаты, уровень логированияWARNилиINFO.
Базовый пример с файлами настроек
Spring Boot автоматически подхватывает файл вида application-{profile}.yml в дополнение к базовому application.yml:
# application.yml (Общие настройки для всех окружений)
server:
port: 8080
---
# application-dev.yml (Только для профиля dev)
spring:
datasource:
url: jdbc:h2:mem:devdb
---
# application-prod.yml (Только для профиля prod)
spring:
datasource:
url: jdbc:postgresql://prod-db.internal:5432/orders
Как активировать профиль
- Через аргумент командной строки при запуске JAR:
java -jar app.jar --spring.profiles.active=prod - Через переменную окружения ОС (стандарт в Docker и Kubernetes):
export SPRING_PROFILES_ACTIVE=prod - Через системный параметр JVM:
java -Dspring.profiles.active=prod -jar app.jar
🟡 Middle Level
Аннотация @Profile над классами и @Bean-методами
Аннотация @Profile указывает контейнеру создавать бин только в том случае, если указанный профиль активен:
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class NotificationConfig {
@Bean
@Profile("dev") // Создается только при активном профиле dev
public EmailSender mockEmailSender() {
return new MockEmailSender(); // Выводит письма в консоль
}
@Bean
@Profile("prod") // Создается только в prod
public EmailSender realEmailSender() {
return new SmtpEmailSender(); // Отправляет реальные письма через почтовый сервер
}
}
Сложные логические выражения в @Profile (Spring 5.1+)
Начиная со Spring 5.1, аннотация @Profile поддерживает операторы булевой логики:
!— логическое НЕ (NOT)&— логическое И (AND)|— логическое ИЛИ (OR)- Скобки
()для группировки приоритетов
@Component
@Profile("prod & !cloud") // Активен в prod, но только если мы НЕ в облаке
public class OnPremiseMonitoringService { }
@Component
@Profile("dev | test") // Активен в dev ИЛИ в test
public class TestDataSeeder { }
@Component
@Profile("prod & (aws | gcp)") // Сложное составное условие
public class CloudStorageAdapter { }
Мульти-документные YAML файлы (Spring Boot 2.4+)
В современном Spring Boot все профили можно описать в одном файле application.yml, разделяя блоки разделителем --- и директивой spring.config.activate.on-profile:
server:
port: 8080
spring:
application:
name: order-service
---
spring:
config:
activate:
on-profile: dev
datasource:
url: jdbc:h2:mem:testdb
---
spring:
config:
activate:
on-profile: prod
server:
port: 443
spring:
datasource:
url: jdbc:postgresql://cluster.prod:5432/main
🔴 Senior Level
Группы профилей (Profile Groups)
В микросервисных системах отдельный сервис может требовать включения сразу нескольких аспектов (кэш, метрики, интеграция с Kafka). Вместо перечисления десятка профилей в строке запуска (--spring.profiles.active=prod,metrics,kafka,redis) настраивают Profile Groups:
# application.yml
spring:
profiles:
group:
production:
- prod
- metrics
- audit
- redis-cache
local-dev:
- dev
- h2-console
- mock-external-apis
Теперь при передаче --spring.profiles.active=production Spring автоматически активирует все четыре связанных профиля.
Приоритет переопределения свойств (Property Precedence)
Если одно и то же свойство (например, server.port) объявлено в нескольких местах, Spring Boot применяет строгую иерархию приоритетов (от наивысшего к низшему):
1. Аргументы командной строки (--server.port=9090)
↓
2. Системные параметры JVM (-Dserver.port=9090)
↓
3. Переменные окружения ОС (SERVER_PORT=9090)
↓
4. Профиль-специфичные файлы вне JAR (config/application-prod.yml)
↓
5. Профиль-специфичные файлы внутри JAR (application-prod.yml)
↓
6. Дефолтные файлы конфигурации вне JAR (config/application.yml)
↓
7. Дефолтные файлы конфигурации внутри JAR (application.yml)
Правило: Настройки из
application-prod.ymlвсегда переопределяют совпадающие свойства из базовогоapplication.yml.
Profiles vs Feature Flags: Архитектурная граница
Частая ошибка архитекторов — попытка использовать Spring Profiles для динамического включения бизнес-фичей.
| Критерий | Spring Profiles | Feature Flags (Toggles) |
|---|---|---|
| Что настраивают | Инфраструктура (БД, брокеры, окружения) | Бизнес-логика (новый UI, алгоритм скидок) |
| Время переключения | Строго при старте JVM (требует рестарта) | В рантайме на лету (без рестарта за секунду) |
| Инструменты | Spring Environment, K8s ConfigMaps | LaunchDarkly, Unleash, Togglz, Redis |
| Гранулярность | На уровне всего приложения / Pod | Для конкретных пользователей или процентов трафика (Canary) |
Защита от запуска Prod без профиля (Fail-Fast Validation)
Если забыть указать профиль при развертывании в Kubernetes, приложение запустится с профилем default (который часто настроен на тестовую БД или H2 в памяти), что приведет к аварии.
Паттерн обязательной валидации профиля:
package com.example.init;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Arrays;
public class MandatoryProfileEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String[] activeProfiles = environment.getActiveProfiles();
// Если запущено не в тесте и ни один профиль не активен — аварийная остановка!
if (activeProfiles.length == 0) {
throw new IllegalStateException(
"ФАТАЛЬНАЯ ОШИБКА: Приложение не может быть запущено без указания активного профиля! "
+ "Задайте переменную SPRING_PROFILES_ACTIVE (например: dev, stage, prod)."
);
}
}
}
🎯 Шпаргалка для интервью
30-секундный ответ
Spring Profiles — инструмент сегментации конфигурации приложения под разные окружения (
dev,stage,prod).
- Позволяет активировать профиль-специфичные файлы настроек (
application-{profile}.yml), свойства которых имеют приоритет над базовымapplication.yml.- Аннотация
@Profileнад классами и@Bean-методами условно регистрирует бины в контексте. Начиная со Spring 5.1, поддерживаются логические выражения (prod & !cloud,dev | test).- В Spring Boot 2.4+ появились Profile Groups (
spring.profiles.group) для объединения наборов профилей и мультидокументные YAML-файлы.- Профили задаются при старте JVM и не предназначены для динамического переключения бизнес-фичей на лету (для этого используются Feature Flags).
4 каверзных вопроса с ответами
-
Как работают логические операторы в аннотации
@Profileи с какой версии Spring они доступны? Ответ: Начиная со Spring Framework 5.1, в строке@Profileможно использовать операторы&(логическое И),|(логическое ИЛИ),!(логическое НЕ) и круглые скобки для группировки условий (например:@Profile("(dev | test) & !docker")). Если условие ложно,ProfileConditionотбраковывает регистрациюBeanDefinition. -
В чём разница в приоритете между
application.ymlиapplication-prod.yml? Ответ: При активном профилеprodсначала загружается базовыйapplication.yml, а затем поверх него накатываетсяapplication-prod.yml. Если одно и то же свойство объявлено в обоих файлах, значение изapplication-prod.ymlпереопределит дефолтное. -
Что такое Profile Groups в Spring Boot? Ответ: Механизм группировки, появившийся в Spring Boot 2.4. Позволяет через свойство
spring.profiles.group.{groupName}объявить составной псевдоним для набора профилей (например: группаproductionавтоматически активирует профилиprod,db-postgres,metrics-datadog). -
В чём принципиальная разница между Spring Profiles и Feature Flags? Ответ: Profiles определяют статическую инфраструктурную конфигурацию и требуют обязательного перезапуска JVM для смены окружения. Feature Flags (фиче-тогглы) управляют поведением бизнес-логики и переключаются динамически в рантайме без перезапуска сервиса (часто индивидуально для конкретных пользователей).
Красные флаги (чего категорически нельзя говорить)
- ❌ «Профили можно динамически переключать в рантайме без перезагрузки JVM» — профили определяют состав бинов в контексте, который замораживается после вызова
context.refresh(). - ❌ «Feature Flags и Spring Profiles — это одно и то же» — флаги меняют логику на лету, профили конфигурируют инфраструктуру на старте.
- ❌ «Секретные пароли и токены продакшена безопасно коммитить в
application-prod.yml» — секреты должны внедряться через переменные окружения, HashiCorp Vault или Kubernetes Secrets. - ❌ «Базовый
application.ymlимеет приоритет надapplication-prod.yml» — профильный файл всегда имеет приоритет над базовым.