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

الملفات الشخصية في Spring Boot

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

الملفات الشخصية في Spring Boot

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

ما هو الملف الشخصي

الملف الشخصي هو مجموعة مسماة من الإعدادات يُفعّلها Spring عند الطلب. عندما يكون ملف شخصي نشطًا، تُحمَّل أي beans أو ملفات خصائص أو فئات إعداد مرتبطة بذلك الملف الشخصي، ويُتجاهل كل شيء آخر. فكّر في الأمر كمجموعة تجاوزات تُطبَّق فوق الإعداد الأساسي.

أسماء الملفات الشخصية الشائعة في المشاريع الحقيقية:

  • dev — التطوير المحلي (قاعدة بيانات H2 في الذاكرة، تسجيل مطوَّل، بدون بريد إلكتروني حقيقي)
  • test — الاختبارات الآلية (H2 أو Testcontainers، بدء تشغيل سريع)
  • staging — بيئة التكامل التي تعكس هيكل الإنتاج
  • prod — الإنتاج (قواعد بيانات حقيقية، تجمعات اتصالات، أسرار من vault)
يمكن تفعيل عدة ملفات شخصية في آنٍ واحد. يمكنك تفعيل كل من prod وeu-west معًا لدمج إعدادات جاهزة للإنتاج مع إعدادات إقليمية خاصة بإقامة البيانات. يدمج Spring خصائصها وـ beans، وتفوز الملفات الشخصية المدرجة لاحقًا عند التعارض.

ملفات الخصائص الخاصة بالملف الشخصي

أبسط طريقة لتوفير قيم خاصة بملف شخصي هي ملف خصائص مخصص. يتبع Spring Boot اتفاقية تسمية تلقائية:

application.properties # الأساسي — يُحمَّل دائمًا application-dev.properties # يُحمَّل فقط عند تفعيل "dev" application-staging.properties # يُحمَّل فقط عند تفعيل "staging" application-prod.properties # يُحمَّل فقط عند تفعيل "prod"

ضع الملفات الأربعة في src/main/resources. يحتوي الملف الأساسي على القيم الافتراضية؛ تتجاوز الملفات الخاصة بالملف الشخصي تلك القيم أو تضيف إليها. إليك تقسيمًا نموذجيًا:

# application.properties (الأساسي) spring.application.name=inventory-service server.port=8080 logging.level.root=INFO
# application-dev.properties spring.datasource.url=jdbc:h2:mem:devdb spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=true logging.level.com.example=DEBUG
# application-prod.properties spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USER} spring.datasource.password=${DB_PASS} spring.datasource.hikari.maximum-pool-size=20 logging.level.root=WARN

لاحظ أن application-prod.properties يُفوّض بيانات الاعتماد إلى متغيرات البيئة عبر صيغة العنصر النائب ${VAR}. يتحكم ملف الملف الشخصي في وجود الإعدادات؛ أما الأسرار فتُحقن في وقت النشر.

تفعيل الملف الشخصي

هناك عدة طرق لإخبار Spring Boot بالملف الشخصي الذي يجب استخدامه:

1. متغير البيئة (مفضَّل في الحاويات وCI/CD):

SPRING_PROFILES_ACTIVE=prod java -jar inventory-service.jar

2. خاصية نظام JVM:

java -Dspring.profiles.active=prod -jar inventory-service.jar

3. في application.properties (للإعدادات الافتراضية المحلية فقط):

spring.profiles.active=dev

4. في الاختبارات مع @ActiveProfiles:

import org.springframework.test.context.ActiveProfiles; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest @ActiveProfiles("test") class OrderServiceTest { // يحمّل Spring تلقائيًا application-test.properties }
لا تلتزم بـ spring.profiles.active=prod في ملف خصائص مشترك. الملف الشخصي النشط قرار تشغيلي لا قرار برمجي. اضبطه في خط أنابيب النشر (Docker ENV أو متغير Kubernetes أو خطوة CI/CD) حتى يمكن ترقية نفس الأداة من التجريب إلى الإنتاج دون إعادة البناء.

الـ Beans الخاصة بالملف الشخصي مع @Profile

الملفات الشخصية ليست للخصائص فقط. يمكنك تقييد تسجيل beans Spring بأكملها على ملف شخصي باستخدام تعليق @Profile. هذا قوي عندما تحتاج إلى تنفيذ مختلف كليًا في بيئات مختلفة — مثلًا مُرسِل بريد إلكتروني حقيقي في الإنتاج وكعب وهمي لا يفعل شيئًا محليًا.

import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; public interface NotificationService { void send(String recipient, String message); } // يُسجَّل فقط عندما يكون الملف الشخصي "prod" نشطًا @Service @Profile("prod") public class SmtpNotificationService implements NotificationService { @Override public void send(String recipient, String message) { // منطق SMTP الحقيقي System.out.println("Sending email to " + recipient); } } // نشط في كل الملفات الشخصية ما عدا prod (لاحظ ! للنفي) @Service @Profile("!prod") public class LoggingNotificationService implements NotificationService { @Override public void send(String recipient, String message) { System.out.println("[DEV] Would send to " + recipient + ": " + message); } }

البادئة ! تعني النفي. يمكنك أيضًا استخدام الصيغة @Profile({"prod", "staging"}) لتفعيل bean عند نشاط أيٍّ من الملفين الشخصيين، أو @Profile("prod & cloud") لاشتراط نشاطهما معًا.

مجموعات الملفات الشخصية (Spring Boot 2.4+)

بدءًا من Spring Boot 2.4، يمكنك تعريف مجموعات الملفات الشخصية — اسم رفيع المستوى يتوسّع إلى عدة ملفات شخصية محددة. هذا يتجنب إجبار المتصلين على تذكّر قائمة طويلة من الأسماء المفصولة بفواصل.

# application.properties spring.profiles.group.production=prod,monitoring,cloud-aws spring.profiles.group.local=dev,seed-data

الآن عند التشغيل بـ SPRING_PROFILES_ACTIVE=production يُفعَّل تلقائيًا prod وmonitoring وcloud-aws معًا. يبقى خط أنابيب CI/CD نظيفًا، ويمكن لكل ملف شخصي فرعي أن يركّز على اهتمام واحد.

الملف الشخصي الافتراضي

إذا لم يُفعَّل أي ملف شخصي، يستخدم Spring الملف الشخصي المدمج default. أي bean مزيّن بـ @Profile("default") يُسجَّل فقط عندما لا يكون شيء آخر نشطًا. هذا شبكة أمان ملائمة لضمان وجود beans على الأقل أثناء التشغيل السريع غير الرسمي، لكن في الممارسة العملية معظم الفرق دائمًا تضبط ملفًا شخصيًا نشطًا صريحًا.

احذر من الـ beans التي لا تحمل ملفًا شخصيًا وتعمل عن طريق الخطأ في الإنتاج. إذا عرّفت bean بدون @Profile، فإنها تُحمَّل في كل بيئة — بما فيها الإنتاج. Bean لحشو بيانات التطوير تفتقر إلى @Profile("dev") قد تُدرج بيانات اختبارية في الإنتاج بصمت في عملية النشر التالية.

فحص الملف الشخصي النشط في وقت التشغيل

يمكنك حقن الملفات الشخصية النشطة حاليًا برمجيًا عبر تجريد Environment:

import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component public class ProfileReporter { private final Environment env; public ProfileReporter(Environment env) { this.env = env; } public void report() { String[] active = env.getActiveProfiles(); System.out.println("Active profiles: " + String.join(", ", active)); } }

هذا مفيد بشكل خاص في رسائل سجل بدء التشغيل أو نقاط نهاية الإدارة لجعل البيئة التي تنتمي إليها النسخة المشغّلة واضحةً فورًا.

الخلاصة

تتيح لك ملفات Spring الشخصية شحن أداة واحدة وتكييف سلوكها لكل بيئة دون لمس الكود. سمِّ ملفاتك الشخصية بوضوح (dev وtest وstaging وprod)، وأبعِد بيانات الاعتماد عن جميع ملفات الملفات الشخصية (فوّضها إلى متغيرات البيئة)، وفعّل الملف الشخصي الصحيح من خط أنابيب النشر لا من المصدر الملتزَم به. استخدم @Profile على الـ beans لتبديل التنفيذات، ومجموعات الملفات الشخصية لتركيب بيئات معقدة من كتل بناء مركّزة. في الدرس التالي سترى كيف يوفر YAML بديلًا أكثر تنظيمًا وإيجازًا لملفات الخصائص، بما في ذلك YAML متعدد الوثائق للاحتفاظ بجميع الملفات الشخصية في ملف واحد.