دورة حياة التطبيق والـ Runners
دورة حياة التطبيق والـ Runners
يمرّ كل تطبيق Spring Boot بدورة حياة محدّدة بدقة منذ اللحظة التي يُستدعى فيها SpringApplication.run() حتى خروج JVM. إنّ فهم هذه الدورة يُمكّنك من الربط بالمرحلة الصحيحة تمامًا — سواء أردت تشغيل فحص قاعدة بيانات قبل أول طلب، أو تهيئة بيانات أوّلية، أو تنفيذ إيقاف تشغيل نظيف. يتناول هذا الدرس تسلسل الإقلاع الداخلي وواجهتَي runner — CommandLineRunner وApplicationRunner — اللتان تُعدّان الطريقة الموصى بها لتنفيذ الكود بعد اكتمال تهيئة سياق التطبيق بالكامل.
ما الذي يحدث داخل SpringApplication.run()؟
عندما تستدعي main التابع SpringApplication.run(MyApp.class, args)، يجري التسلسل التالي (بصورة مبسّطة):
- مرحلة الإقلاع: يُحمّل Spring الـ
SpringApplicationRunListeners ويُطلق حدثstarting(). - تحضير البيئة: يتمّ دمج
application.properties/.ymlومتغيرات البيئة وسيطات سطر الأوامر في كائنEnvironmentواحد. - إنشاء السياق: يُنشأ النوع المناسب من
ApplicationContext(AnnotationConfigServletWebServerApplicationContextلتطبيق الويب، وAnnotationConfigApplicationContextلغيره). - تحميل تعريفات الـ Bean: تُعالَج فئات
@Configurationوتُسجَّل جميع تعريفات الـ Bean. - تحديث السياق: يُنشأ كل bean وتُحقن التبعيات وتُنفَّذ الدوال المُعلَّمة بـ
@PostConstructويُشغَّل الخادم المُدمج. - تنفيذ الـ Runners: تُستدعى جميع الـ
CommandLineRunnerوApplicationRunnerbeans بالترتيب. - الجاهزية: يُنشر الحدث
ApplicationReadyEventويبدأ التطبيق بمعالجة الطلبات.
CommandLineRunner
CommandLineRunner واجهة وظيفية ذات تابع واحد. يستقبل تابعها run(String... args) سيطات سطر الأوامر الخام تمامًا كما مُرّرت إلى main().
نظرًا لكونه @Component عاديًا فهو يشارك في حقن التبعيات كأي bean آخر. يستقبل المُنشئ UserRepository — دون الحاجة إلى حقن حقل.
ApplicationRunner
ApplicationRunner شبه مطابق تقريبًا لكنه يستقبل كائن ApplicationArguments بدلًا من مصفوفة String[] خام. هذا أكثر ملاءمةً عندما تُمرّر سيطات منظَّمة من سطر الأوامر.
يُميّز ApplicationArguments بين السيطات الخيارية (المسبوقة بـ -- كـ --env=prod) والسيطات غير الخيارية (السلاسل النصية العادية كـ migrate). يُزيل هذا الحاجة إلى تحليل String[] يدويًا.
التحكم في ترتيب التنفيذ
عند وجود عدة Runners، يُنفّذها Spring Boot وفق الترتيب الذي تُحدّده التعليقة التوضيحية @Order (القيمة الأدنى = الأولوية الأعلى) أو الواجهة Ordered.
@Order لجعل التبعية صريحةً في الكود بدلًا من الاعتماد على ترتيب تسجيل الـ Bean، الذي لا يكون مضمونًا ويتغير بصمت مع نمو قاعدة الكود.
الـ Runners مقابل @PostConstruct مقابل ApplicationListener
يوفّر Spring عدة خطاطيف. إليك متى تستخدم كل منها:
@PostConstruct— يُنفَّذ مباشرةً بعد بناء bean واحدة، قبل اكتمال تهيئة الـ beans الأخرى التي تعتمد عليه. استخدمه للإعداد المحلي لـ bean (تهيئة ذاكرة تخزين مؤقتة داخلية، التحقق من خاصية تهيئة). لا تستخدمه لأي شيء يتطلب تشغيلًا كاملًا لـ beans أخرى كبدء خيط خلفية يلمس قاعدة البيانات.CommandLineRunner/ApplicationRunner— يُنفَّذان بعد اكتمال تحديث السياق بالكامل وانطلاق الخادم. استخدمهما لمهام الإقلاع التي تلمس beans متعددة أو العالم الخارجي: ترحيل قواعد البيانات، تسخين الكاش، فحوصات الصحة، أوامر نمط CLI.ApplicationListener<ApplicationReadyEvent>— يُطلق في نفس نقطة الـ Runners لكن عبر نظام الأحداث. مفيد عندما يقع منطق الإقلاع في طبقة بنية تحتية لا ينبغي لها معرفة واجهات Runner. الـ Runners أبسط بوجه عام وهي المُفضَّلة لكود طبقة التطبيق.
نمط عملي: تهيئة البيانات المشروطة
نمط شائع في الواقع هو تهيئة البيانات فقط عند تفعيل Spring profile معيّن، لتجنّب الإدراج العرضي للبيانات في بيئة الإنتاج:
System.exit(1). هذا ما تريده عادةً لفحص إقلاع حرج، لكنه مُفاجئ إذا كان الاستثناء عرضيًا. عالج الأخطاء المتوقعة بشكل صريح ودع الحالات غير القابلة للاسترداد فقط تنتشر.
اختبار الـ Runners
يمكنك استبعاد الـ Runners من اختبارات معيّنة باستبعاد فئة الـ bean أو استخدام @SpringBootTest مع مسح مكوّنات انتقائي. أو اختبر الـ runner مباشرةً بإنشائه مع تبعيات وهمية (mock):
الخلاصة
تسلسل إقلاع Spring Boot محدّد ومُنظَّم. CommandLineRunner هو الواجهة المثلى عندما تحتاج فقط إلى تشغيل كود بعد الإقلاع ولا تحتاج إلى سيطات سطر أوامر منظَّمة. ApplicationRunner هو الاختيار الأفضل عندما تريد تحليل سيطات بأسلوب --option=value بنظافة. كلاهما beans Spring عادية: احقن ما تحتاجه، وعلّم بـ @Order عندما يهمّ الترتيب، وقيّد بـ @Profile لحماية بيئة الإنتاج. في الدرس القادم ستتناول نظام التسجيل المُدمج في Spring Boot وكيفية ضبطه دون لمس ملف logback.xml.