Що таке 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» — профільний файл завжди має пріоритет над базовим.