الخادم المدمج
الخادم المدمج
من أبرز الفوارق بين تطبيق Java الويب التقليدي وتطبيق Spring Boot طريقة تشغيله. في النموذج التقليدي كنت تحزم شيفرتك كملف WAR وتنشره داخل خادم تطبيقات مثبّت بشكل مستقل — Tomcat أو JBoss أو WebLogic. في Spring Boot يُشحن الخادم بداخل ملف JAR الخاص بك. تشغّل java -jar myapp.jar فيبدأ Tomcat من تلقاء نفسه. يشرح هذا الدرس كيف يعمل ذلك بالضبط، ولماذا يهم، وكيف تضبطه أو تستبدله.
معنى "المدمج"
الخادم المدمج هو خادم تطبيقات تديره شيفرة تطبيقك لا العكس. يحقق Spring Boot ذلك بتضمين الخادم كتبعية عادية. حين يستدعي التابع main() التابعَ SpringApplication.run()، تقوم إطار العمل بما يلي:
- إنشاء سياق تطبيق Spring
ApplicationContext. - الكشف عن تبعية الخادم المدمج في مسار الفئات.
- إنشاء الخادم وتهيئته برمجيًا (مثل
org.apache.catalina.startup.Tomcat). - تسجيل
DispatcherServletلديه. - تشغيل الخادم وربطه بمنفذ.
تجري عملية الإقلاع بالكامل داخل عملية JVM. حين تُنهي العملية يتوقف الخادم معها — لا سكريبت إيقاف منفصل، ولا خطوة إلغاء نشر.
الخيارات الثلاثة للخوادم المدمجة
يشحن Spring Boot تهيئة تلقائية لثلاثة خوادم مدمجة. تختار واحدًا بالتحكم في التبعية الموجودة في مسار الفئات:
- Tomcat (الافتراضي) — ناضج وشائع الاستخدام ومُختبَر على نطاق واسع. يُسحب تلقائيًا بواسطة
spring-boot-starter-web. - Jetty — خفيف الوزن، قوي تاريخيًا في التعامل مع الاتصالات طويلة الأمد (WebSocket وبث HTTP/2).
- Undertow — إنتاجية عالية، نواة إدخال/إخراج غير متزامنة، بصمة ذاكرة منخفضة لكل اتصال. شائع لأحمال العمل التفاعلية حتى في مكدس سيرفلت.
للتبديل من Tomcat إلى Undertow تستبعد مُشغّل Tomcat وتضيف مُشغّل Undertow في ملف pom.xml:
لا حاجة لأي تغييرات في الشيفرة — يكتشف Spring Boot الخادم الجديد في مسار الفئات ويوصّله بنفس الطريقة. هذه هي التهيئة التلقائية في عملها.
ضبط الخادم عبر application.properties
تقع أكثر إعدادات الخادم شيوعًا ضمن الفضاء server.* في ملف application.properties (أو application.yml):
server.port=0 إلى تكليف نظام التشغيل بتعيين أي منفذ متاح. هذا مفيد جدًا في اختبارات التكامل — تحصل كل جولة اختبار على منفذ فريد مما يُزيل عدم الاستقرار الناجم عن تعارض المنافذ. أدرج المنفذ الفعلي المختار في الاختبار باستخدام @LocalServerPort.
التخصيص البرمجي للخادم
تغطي الخصائص 80% من حالات الاستخدام. لما تبقى — موصّلات مخصصة وصفحات خطأ مخصصة وضغط Gzip مضبوط بما يتجاوز ما تتيحه الخصائص — تنفّذ واجهة WebServerFactoryCustomizer. النسخة العامة تعمل مع الخوادم الثلاثة؛ أما الواجهات الفرعية الخاصة بكل خادم فتتيح الوصول إلى واجهات برمجية من مورّد بعينه:
application.properties للإعدادات القياسية. احتفظ بـ WebServerFactoryCustomizer للأشياء التي ليس لها خاصية مقابلة حقًا. المخصّصات التي تستخدم الواجهة الخاصة بالخادم (مثل TomcatServletWebServerFactory) ستتعطل إذا استبدلت الخادم لاحقًا؛ أما ConfigurableServletWebServerFactory العامة فهي محمولة.
الإيقاف الأنيق
بشكل افتراضي، حين يستقبل Spring Boot إشارة إيقاف (SIGTERM) يوقف الخادم فورًا — تُقطع الطلبات الجارية. منذ Spring Boot 2.3 يمكنك تفعيل الإيقاف الأنيق الذي يسمح للطلبات النشطة بالاكتمال قبل خروج العملية:
مع server.shutdown=graceful يتوقف الخادم عن قبول اتصالات جديدة فور وصول الإشارة لكنه يكمل معالجة الطلبات الجارية بالفعل حتى حد المهلة timeout-per-shutdown-phase. هذا ضروري للنشر المتدرج بدون توقف في Kubernetes أو خلف موازن حمل.
ملف JAR القابل للتنفيذ وآلية عمله
حين تشغّل mvn package (أو ./gradlew bootJar) ينشئ إضافة البناء في Spring Boot ملف fat JAR — أرشيف واحد يحتوي على فئاتك المُجمَّعة وجميع ملفات JAR للتبعيات (بما فيها JAR الخادم) ومشغّل مخصص. يفهم المشغّل ملفات JAR المتداخلة (فأداة تحميل الفئات القياسية في Java لا تفهمها)، يحمّلها جميعًا ثم يستدعي التابع main() لفئة @SpringBootApplication.
هيكل ملف JAR الموسّع داخل الأرشيف كالتالي:
نشر WAR: متى لا تزال بحاجة إليه
بعض المنظمات تشغّل خادم Tomcat أو JBoss مشتركًا تديره العمليات. في هذه الحالة تنتج WAR بدلًا من JAR. غيّر نوع التعبئة في pom.xml، ومدّد SpringBootServletInitializer، وضع نطاق الخادم المدمج على provided:
main() لا يزال موجودًا، يعمل المشروع ذاته كملف JAR قابل للتنفيذ في التطوير ويمكن نشره كملف WAR في الإنتاج. نطاق provided على مُشغّل Tomcat يعني استبعاده من WAR (الحاوية توفّره) مع بقائه في مسار الفئات عند التشغيل محليًا عبر main().
الخلاصة
يدمج Spring Boot Tomcat (أو Jetty أو Undertow) كمكتبة داخل ملف JAR، مما يجعل java -jar وحدة النشر الكاملة. تضبط الخادم عبر فضاء الخصائص server.* للإعدادات الشائعة وعبر WebServerFactoryCustomizer للضبط المتقدم. الإيقاف الأنيق مع مهلة مُهيَّأة ضرورة لأي حمل إنتاجي يتوقع إعادة التشغيل دون توقف. حين تفرض القيود المؤسسية استخدام حاوية خارجية، يتطلب التبديل إلى تعبئة WAR ثلاثة تغييرات صغيرة فقط مع الإبقاء على شجرة المصدر ذاتها.