الإعداد والملفّات الشخصية وActuator

الإعدادات الخارجية في Spring Boot

18 دقيقة الدرس 1 من 13

الإعدادات الخارجية في Spring Boot

من أهم ميزات Spring Boot في بيئة الإنتاج الإعدادات الخارجية (Externalized Configuration): القدرة على تغيير سلوك التطبيق دون إعادة تصريفه (compile) أو نشره من جديد. عناوين URL لقاعدة البيانات، ومفاتيح API، وأعلام الميزات، وأحجام تجمّعات الخيوط — لا مكان لأيٍّ من هذه القيم داخل ملف JAR. يوفّر Spring Boot نظامًا طبقيًا غنيًا من مصادر الخصائص (property sources) حتى يعمل المصنَّف الثنائي نفسه بشكل صحيح في بيئة التطوير المحلية وبيئة التكامل المستمر والاختبار والإنتاج، وذلك بمجرد توفير قيم مختلفة عند بدء التشغيل.

التجريد الأساسي: PropertySource

في قلب هذا النظام تقع org.springframework.core.env.PropertySource<T>. كل مكان يمكن أن تأتي منه خاصية — ملف، متغير بيئة، وسيطة سطر أوامر، قاعدة بيانات — يُنمذَج كـ PropertySource. تحتفظ Environment في Spring بقائمة مُرتَّبة من هذه المصادر وتُجيب على طلبات البحث بالمسح من المصدر الأعلى أولوية إلى الأدنى، وتُعيد أول قيمة تجدها.

نادرًا ما تتفاعل مع PropertySource مباشرةً. بدلًا من ذلك تتعامل مع مستهلكَيها الرئيسيَّين:

  • @Value("${some.key}") — تحقن خاصية واحدة في حقل أو معامل مُنشئ.
  • Environment.getProperty("some.key") — بحث برمجي في أي مكان يتوفر فيه الـ bean الخاص بـ Environment.

ترتيب الأولوية (من الأعلى إلى الأدنى)

يُعرّف Spring Boot 17 مصدر خصائص قياسيًا. في الممارسة اليومية، المصادر التي ستتعامل معها هي (من الأعلى إلى الأدنى أولوية):

  1. وسيطات سطر الأوامر (--server.port=9090)
  2. SPRING_APPLICATION_JSON — JSON مضمَّن في متغير بيئة أو خاصية نظام
  3. معاملات تهيئة حاوية Servlet (في حالة النشر على حاوية خارجية)
  4. متغيرات بيئة نظام التشغيل (SPRING_DATASOURCE_URL=...)
  5. خصائص نظام JVM (-Dspring.datasource.url=...)
  6. ملفات الخصائص الخارجية للـ JARapplication-{profile}.properties و application.properties بجانب الـ JAR
  7. ملفات الخصائص المحزومة داخل الـ JAR — المعبأة في src/main/resources
  8. تعليقات @PropertySource على فئات @Configuration
  9. الخصائص الافتراضية المعيَّنة عبر SpringApplication.setDefaultProperties
القاعدة الأساسية: المصدر الأعلى في القائمة يفوز دائمًا. متغير بيئة نظام التشغيل الذي يحمل الاسم ذاته لخاصية موجودة في application.properties سيتجاوزها. هذا تصميم مقصود — يتيح لمشغّلي الأنظمة تجاوز الإعدادات الافتراضية للمطوّرين وقت النشر دون لمس كود المصدر.

application.properties — ملفك اليومي

أكثر المصادر شيوعًا هو src/main/resources/application.properties. يكتشفه Spring Boot تلقائيًا. يمكن وضع أي مفتاح خاص بـ Spring أو مكتبة خارجية فيه:

# الخادم server.port=8080 server.servlet.context-path=/api # مصدر البيانات (تُستبدل القيم في الإنتاج بمتغيرات البيئة) spring.datasource.url=jdbc:postgresql://localhost:5432/shopdb spring.datasource.username=appuser spring.datasource.password=secret # JPA spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=validate # مفتاح خاص بالتطبيق app.payments.gateway-url=https://sandbox.payments.example.com app.payments.timeout-seconds=10

لاحظ الربط المرن (relaxed binding): يُطبّع Spring Boot أسماء المفاتيح، لذا فإن app.payments.timeout-seconds و APP_PAYMENTS_TIMEOUT_SECONDS (صيغة متغير البيئة) و app.payments.timeoutSeconds تُحلَّل كلها إلى الخاصية ذاتها. هذا ما يجعل متغيرات البيئة تعمل بسلاسة كتجاوزات.

حقن القيم باستخدام @Value

import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class PaymentClient { private final String gatewayUrl; private final int timeoutSeconds; public PaymentClient( @Value("${app.payments.gateway-url}") String gatewayUrl, @Value("${app.payments.timeout-seconds:30}") int timeoutSeconds) { this.gatewayUrl = gatewayUrl; this.timeoutSeconds = timeoutSeconds; } }

اللاحقة :30 هي قيمة افتراضية — إذا كانت الخاصية غائبة، يستخدم Spring القيمة 30 بدلًا من رمي خطأ عند بدء التشغيل. اذكر دائمًا قيمة افتراضية منطقية للخصائص الاختيارية، واتركها بدون قيمة افتراضية للخصائص المطلوبة حتى تُكتشف الإعدادات المفقودة فورًا عند التشغيل.

فضّل حقن المُنشئ على حقن الحقل مع @Value. القيم المحقونة عبر المُنشئ تُعيَّن قبل استخدام الـ bean، وتجعل التبعيات صريحة، وتتيح اختبار الفئة باختبارات وحدة دون سياق Spring بمجرد تمرير القيم مباشرةً.

البحث البرمجي باستخدام Environment

حين تحتاج إلى قراءة خاصية خارج bean مُدار، أو حين يكون المفتاح معروفًا فقط في وقت التشغيل، احقن org.springframework.core.env.Environment:

import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @Service public class FeatureFlagService { private final Environment env; public FeatureFlagService(Environment env) { this.env = env; } public boolean isEnabled(String flagName) { return env.getProperty("feature." + flagName, Boolean.class, false); } }

التجاوز في وقت التشغيل — أمثلة عملية

بما أن وسيطات سطر الأوامر ومتغيرات البيئة تعلو الملفات، يمكنك تجاوز أي خاصية دون تغيير كود المصدر.

تجاوز سطر الأوامر (اختبار محلي):

java -jar shop-1.0.jar --server.port=9090 --spring.datasource.password=testpw

تجاوز متغيرات البيئة (Docker / Kubernetes):

# في أمر docker run أو كتلة env: في Kubernetes SPRING_DATASOURCE_URL=jdbc:postgresql://prod-db:5432/shopdb SPRING_DATASOURCE_PASSWORD=prodSecret SERVER_PORT=8080

يُعيِّن Spring Boot تعيين أسماء متغيرات البيئة إلى أسماء الخصائص بتحويلها إلى أحرف صغيرة واستبدال الشرطات السفلية بنقاط: SPRING_DATASOURCE_URLspring.datasource.url. يُسمَّى هذا الربط المرن (relaxed binding) ويعمل في الاتجاهين.

ملفات الخصائص الخارجية للـ JAR

عندما تضع ملف application.properties (أو application.yml) في المجلد نفسه الذي يحتوي على ملف JAR — أو في مجلد فرعي config/ — يلتقطه Spring Boot تلقائيًا ويمنحه أولوية أعلى من النسخة المعبأة. هذا الأسلوب Unix-admin التقليدي في الإعداد لكل خادم:

/opt/apps/shop/ shop-1.0.jar config/ application.properties <-- يتجاوز النسخة المعبأة
لا تضع كلمات المرور في ملفات الخصائص المحفوظة في نظام التحكم في الإصدارات أبدًا. يجب أن يحتوي ملف application.properties المعبأ فقط على قيم افتراضية آمنة. يجب أن تصل الأسرار عبر متغيرات البيئة أو خادم إعدادات خارجي أو مدير أسرار (AWS Secrets Manager أو HashiCorp Vault أو Kubernetes Secrets) — وكل هذا مُغطَّى لاحقًا في هذا البرنامج التعليمي.

كيف تعمل الطبقات معًا

في إعداد إنتاج نموذجي، تُكمل الطبقات بعضها:

  • application.properties المعبأ — قيم افتراضية آمنة تعمل في بيئة التطوير (server.port=8080، spring.jpa.show-sql=true).
  • ملفات خاصة بالبروفايل (application-prod.properties) — تجاوزات إنتاجية غير سرية (spring.jpa.show-sql=false). تُفعَّل بواسطة متغير البيئة SPRING_PROFILES_ACTIVE=prod.
  • متغيرات بيئة نظام التشغيل — الأسرار ونقاط نهاية البنية التحتية التي يُدخلها مشغّل النظام وقت النشر، ولا تُودَع في git أبدًا.
  • وسيطات سطر الأوامر — تجاوزات لمرة واحدة أثناء التصحيح المحلي أو اختبارات الدخان.

الخلاصة

إعدادات Spring Boot الخارجية مبنية على قائمة مُرتَّبة من كائنات PropertySource. المصادر الأعلى أولوية (سطر الأوامر، متغيرات البيئة) تفوز دائمًا على الأدنى (الملفات المعبأة). سير عملك اليومي هو: احتفظ بالقيم الافتراضية الآمنة في application.properties، واستبدل الأسرار والقيم الخاصة بالبيئة عبر متغيرات بيئة نظام التشغيل أو خادم إعدادات، واستخدم @Value أو Environment لاستهلاك الخصائص في الـ beans. الدرس التالي ينتقل من الخصائص الفردية إلى ربط مجموعات كاملة منها في فئات إعداد ذات أنواع محكمة باستخدام @ConfigurationProperties.