إدارة التهيئة
إدارة التهيئة هي الجسر بين التطوير والإنتاج—قاعدة كود واحدة، تهيئات متعددة، والتبديل بين البيئات يتطلب معاملاً واحداً فقط.
1. ما ستتعلمه
- آلية Profile:
application-dev.yml/application-prod.ymlالتبديل بين البيئات المتعددة - مقارنة الربط الآمن بالأنواع
@ConfigurationPropertiesوالحقن@Value - ترتيب أولوية التهيئة: معاملات سطر الأوامر > متغيرات البيئة > ملفات التهيئة > القيم الافتراضية
- التهيئة المتداخلة والربط بأنواع List/Map
- أفضل الممارسات لتوطين تهيئة مصدر بيانات OrderFlow ومفاتيح API الخارجية
2. قصة حقيقية لمهندس عمليات
(1) نقطة الألم: التهيئات متناثرة في كل مكان
Bob هو مهندس عمليات في OrderFlow، وكل نشر يبدو وكأنه "حفريات أثرية": كلمات مرور قاعدة البيانات مشفرة بشكل ثابت في الكود، وتهيئات بيئتي الاختبار والإنتاج مختلطة في ملف واحد. غيّر أحدهم كلمة مرور قاعدة بيانات الإنتاج لكنه نسي تحديث الكود، مما أدى إلى توقف النظام لساعتين. عندما ضغط عليه Charlie بشأن SLA، لم يتمكن Bob إلا من التوضيح، بتنهيدة، أن "إدارة التهيئة فوضوية."
(2) حلول Spring Boot Profiles
Spring Boot يستخدم آلية Profile لفصل تهيئات البيئات المتعددة:
# 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) العوائد
بعد أن أعاد Bob بناء الكود باستخدام Profile ومتغيرات البيئة، أصبحت بيئة التطوير تستخدم dev وبيئة الإنتاج تستخدم prod. المعلومات الحساسة لم تعد تظهر في مستودع الكود، والتبديل بين النشرات يتطلب فقط --spring.profiles.active=prod، مما قلل وقت التوقف الناجم عن أخطاء التهيئة إلى الصفر.
3. Profile: تهيئة البيئات المتعددة
(1) اصطلاحات تسمية ملفات Profile
Spring Boot يحمل تهيئات Profile وفقاً لاصطلاح التسمية application-{profile}.yml:
src/main/resources/
├── application.yml # تهيئة مشتركة
├── application-dev.yml # ملف تعريف التطوير
├── application-prod.yml # ملف تعريف الإنتاج
└── application-test.yml # ملف تعريف الاختبار
graph TD
A["application.yml<br/>تهيئة مشتركة"] --> B["application-dev.yml<br/>تجاوزات التطوير"]
A --> C["application-prod.yml<br/>تجاوزات الإنتاج"]
A --> D["application-test.yml<br/>تجاوزات الاختبار"]
B --> E["تهيئة مدمجة<br/>Profile=dev"]
C --> F["تهيئة مدمجة<br/>Profile=prod"]
| طريقة التفعيل | الأمر | الأولوية |
|---|---|---|
| ملف التهيئة | spring.profiles.active=dev في application.yml |
الحد الأدنى |
| متغير البيئة | SPRING_PROFILES_ACTIVE=dev |
متوسطة |
| معامل سطر الأوامر | --spring.profiles.active=dev |
الحد الأقصى |
(1) ▶ مثال: Profile
# application.yml (مشترك)
spring:
application:
name: orderflow-service
profiles:
active: dev
server:
port: 8080
الناتج:
تم تطبيق التهيئة بنجاح
# 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. مقارنة بين @Value و@ConfigurationProperties
(1) طريقتا الحقن
(1) ▶ مثال: حقن @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
);
}
}
الناتج:
// التنفيذ ناجح
(2) ▶ مثال: الربط الآمن بالأنواع باستخدام @ConfigurationProperties
@ConfigurationProperties(prefix = "orderflow")
public record OrderFlowProperties(
int maxItemsPerOrder,
String defaultCurrency,
Duration orderTimeout,
ShippingConfig shipping
) {
public record ShippingConfig(
boolean freeShippingEnabled,
BigDecimal freeShippingThreshold
) {}
}
// التفعيل في الصنف الرئيسي أو صنف التهيئة
@EnableConfigurationProperties(OrderFlowProperties.class)
الناتج:
// التنفيذ ناجح
| البُعد | @Value |
@ConfigurationProperties |
|---|---|---|
| أمان الأنواع | ضعيف (أساساً String) | قوي (تحويل أنواع تلقائي) |
| الكائنات المتداخلة | غير مدعوم | مدعوم |
| ربط المجموعات | غير مدعوم | يدعم List/Map |
| التحقق | بدون | بالاقتران مع @Validated |
| دعم IDE | بدون تلميحات | إكمال تلقائي (بيانات وصفية) |
| حالات الاستخدام | عدد قليل من القيم البسيطة | تهيئة أعمال مهيكلة |
(3) ▶ مثال: تعيين YAML وConfigurationProperties
orderflow:
max-items-per-order: 50
default-currency: USD
order-timeout: 30m
shipping:
free-shipping-enabled: true
free-shipping-threshold: 49.99
الناتج:
تم تفعيل التهيئة.
// مثال على الوصول
@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. التسلسل الهرمي لأولوية التهيئة
(1) الأولوية من الأعلى إلى الأدنى
graph TD
A["1. معاملات سطر الأوامر<br/>--server.port=9090"] --> B["2. خصائص JNDI"]
B --> C["3. خصائص نظام Java<br/>-Dserver.port=9090"]
C --> D["4. متغيرات بيئة نظام التشغيل<br/>SERVER_PORT=9090"]
D --> E["5. application-{profile}.yml<br/>خاصة بـ Profile"]
E --> F["6. application.yml<br/>تهيئة افتراضية"]
F --> G["7. @القيم الافتراضية<br/>في تعليقات الكود"]
| الأولوية | المصدر | مثال |
|---|---|---|
| 1 (الأعلى) | معاملات سطر الأوامر | --server.port=9090 |
| 2 | خصائص JNDI | java:comp/env/... |
| 3 | خصائص نظام JVM | -Dserver.port=9090 |
| 4 | متغيرات بيئة نظام التشغيل | SERVER_PORT=9090 |
| 5 | Profile | application-prod.yml |
| 6 | ملف التهيئة الافتراضي | application.yml |
| 7 (الأدنى) | القيمة الافتراضية | @Value("${x:default}") |
6. التهيئة المتداخلة وربط المجموعات
(1) ربط القوائم والخرائط
(1) ▶ مثال: تهيئة List و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}
الناتج:
تم تحميل تهيئة خط أنابيب CI/CD
حالة الخط: ناجح
الاختبارات: 12 ناجح، 0 فاشل
@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. مثال شامل: نظام التهيئة الكامل لـ 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}
❓ أسئلة شائعة
${ENV_VAR} في ملفات التهيئة للإشارة إلى متغيرات البيئة؛ 2) استبعد ملفات التهيئة الحساسة في .gitignore؛ 3) استخدم K8s Secrets أو Vault لإدارة الأسرار في بيئة الإنتاج.orderflow.supported-currencies[0]=USD، orderflow.supported-currencies[1]=EUR. مؤشرات القائمة تبدأ من 0.record كـ ConfigurationProperties؟record غير قابل للتغيير ومناسب للتهيئات للقراءة فقط. Spring Boot 3.x يدعم ربط record. ومع ذلك، لا يمكن استخدامه مع @Validated للتحقق JSR-380 (لأن record يفتقر إلى مُنشئ بدون معاملات)، لذا يجب استخدام صنف بدلاً من ذلك.📖 ملخص
- آلية Profile تُمكّن فصل التهيئة عبر البيئات المتعددة؛
application-{profile}.ymlيتجاوز التهيئة الافتراضية - الربط الآمن بالأنواع
@ConfigurationPropertiesيتفوق على@Valueويدعم التداخل والمجموعات والتحقق - أولوية التهيئة: سطر الأوامر > متغيرات البيئة > ملف Profile > الملف الافتراضي > القيم الافتراضية في الكود
- استخدم العنصر النائب
${ENV_VAR}للمعلومات الحساسة؛ لا تشفرها بشكل ثابت في ملف التهيئة - Spring Boot 3.x يدعم استخدام
recordكـConfigurationProperties
📝 تمارين
-
تمرين أساسي (الصعوبة ⭐): قم بتهيئة ملفي Profile لـ OrderFlow—أحدهما لـ dev والآخر لـ prod. يستخدم ملف dev قاعدة بيانات H2 في الذاكرة، بينما يستخدم ملف prod قاعدة بيانات MySQL. بدّل بينهما باستخدام معاملات سطر الأوامر.
-
مسألة متقدمة (الصعوبة ⭐⭐): استخدم
@ConfigurationPropertiesلإنشاءPaymentGatewayProperties، الذي يتضمن تهيئات مفتاح API لـ Stripe وPayPal؛ حقن قيم المفاتيح عبر متغيرات البيئة. -
تحدٍ (الصعوبة: ⭐⭐⭐): نفّذ
PropertySourceمخصص لتحميل التهيئة من مركز تهيئة بعيد (يمكنك استخدام نقطة نهاية HTTP محاكاة)، وفكّر في الدافع التصميمي وراء تجريدEnvironmentفي Spring Boot.



