إطار Spring وحاوية IoC

ما هو Spring؟

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

ما هو Spring؟

Spring هو إطار العمل الأكثر انتشارًا في نظام Java البيئي. في جوهره مجموعة من المكتبات والاصطلاحات التي تتكفّل بما تحتاجه كل تطبيقات المؤسسات من بنية تحتية — ربط التبعيات، وإدارة المعاملات، والوصول إلى البيانات، والأمان، وبنية الويب — حتى تتفرّغ أنت لكتابة منطق الأعمال بدلًا من الكود المتكرر.

فهم Spring يبدأ بفهم المشكلة التي وُجد لحلّها.

المشكلة التي أوجد Spring لحلّها

قبل Spring، كان المعيار السائد لبناء تطبيقات Java المؤسسية هو J2EE (منصة Java 2 للإصدار المؤسسي). وعد J2EE بإمكانية النقل والنموذج البرمجي الموحّد، غير أنه في الواقع أفرز شيئًا آخر: اقترانًا وثيقًا بين منطق الأعمال والحاوية، وملفات XML ضخمة، وـكيانات EJB يجب أن ترث فئات أساسية من الإطار، واختبارات وحدة تكاد تكون مستحيلة لأن كل كائن يعتمد على خادم تطبيقات يعمل.

تخيّل سيناريو ما قبل Spring: تحتاج إلى خدمة تُنفّذ الطلبات. يجب أن تبحث عن مرجع EJB بعيد وتحوّله وتستدعي الدالة وتمسك بالاستثناءات البعيدة — كل ذلك لمجرد استدعاء دالة على كائن في نفس JVM:

// خدمة J2EE ما قبل Spring — المشاكل واضحة للعيان public class OrderServiceBean implements SessionBean { public void placeOrder(Order order) throws RemoteException { try { Context ctx = new InitialContext(); Object ref = ctx.lookup("java:comp/env/ejb/InventoryService"); InventoryServiceHome home = (InventoryServiceHome) PortableRemoteObject.narrow(ref, InventoryServiceHome.class); InventoryService inventory = home.create(); inventory.reserve(order.getItems()); // أخيرًا — الاستدعاء الفعلي للأعمال } catch (NamingException | CreateException e) { throw new EJBException(e); } } }

المشكلة الحقيقية هنا ليست الإسهاب — بل هي الاقتران الوثيق. يختبئ منطق الأعمال تحت طبقات من البنية التحتية. لا يمكنك اختبار placeOrder دون خادم JNDI وخادم تطبيقات وEJB منشورة. لا يمكنك استبدال تنفيذ المخزون بنسخة وهمية في الاختبار. الكود غير قابل للاختبار بمعزل.

الفكرة الجوهرية في Spring: يجب أن تُعلن الكائنات عمّا تحتاجه، لا أن تذهب وتجلبه بنفسها. ينبغي أن تتلقى الخدمة InventoryService كمعامل في البنّاء — والإطار يوفّر المثيل. هذا هو قلب التحكم، وهو الفكرة التي يقوم عليها Spring.

ما هو Spring فعلًا

Spring ليس مكتبة واحدة — بل نظام بيئي يضمّ أكثر من 20 مشروعًا متخصصًا، كلها مبنية على أساس مشترك يُسمّى Spring Framework (يُشار إليه أحيانًا بـ "Spring Core"). يُقدّم Spring Framework:

  • حاوية IoC — تُنشئ الكائنات (beans) وتربطها معًا محقنةً التبعيات تلقائيًا.
  • البرمجة الموجّهة بالجوانب (AOP) — تُطبّق الاهتمامات المشتركة (التسجيل والأمان والمعاملات) دون تلويث الفئات التجارية.
  • تجريد الوصول إلى البياناتJdbcTemplate وإدارة المعاملات والتكامل مع JPA/Hibernate.
  • Spring MVC — إطار ويب نظيف قائم على التعليقات التوضيحية فوق Servlet API.
  • دعم الاختبارات — أدوات لاختبارات التكامل التي تُشغّل حاوية Spring دون خادم كامل.

حول هذا النواة، يُضيف النظام البيئي الأشمل لـ Spring:

  • Spring Boot — التهيئة التلقائية والخوادم المضمّنة؛ يُتيح تشغيل تطبيق جاهز للإنتاج من main() في دقائق.
  • Spring Security — المصادقة والتفويض وحماية CSRF وOAuth2/OIDC.
  • Spring Data — تجريدات المستودع لـ JPA وMongoDB وRedis وغيرها.
  • Spring Cloud — اكتشاف الخدمات والإعداد الموزّع وقواطع الدائرة للخدمات المصغّرة.
  • Spring Batch — المعالجة القائمة على المقاطع للمهام الدفعية واسعة النطاق.
ابدأ بالإطار لا بالنظام البيئي. Spring Boot مريح، لكن إن تعلّمته أولًا لن تفهم لماذا تعمل الأشياء. يُركّز هذا البرنامج التعليمي على Spring Framework (حاوية IoC) حتى عندما يُولّد Boot الإعداد تلقائيًا تستطيع قراءته وتجاوزه وتصحيح أخطائه.

السيناريو ذاته مع Spring

إليك OrderService ذاتها مُعاد كتابتها كـ bean يُديره Spring. لم يتبقَّ الآن سوى منطق الأعمال:

import org.springframework.stereotype.Service; @Service public class OrderService { private final InventoryService inventoryService; // Spring يحقن التبعية عبر البنّاء public OrderService(InventoryService inventoryService) { this.inventoryService = inventoryService; } public void placeOrder(Order order) { inventoryService.reserve(order.getItems()); } }

لا بحث JNDI. لا اعتمادية على الحاوية. لا RemoteException. الفئة كائن Java عادي. يمكنك إنشاء مثيل منها في اختبار وحدة بتمرير InventoryService وهمي — دون أي خادم تطبيقات:

// اختبار JUnit خالص — لا حاوية Spring على الإطلاق @Test void placeOrder_reservesItems() { InventoryService mockInventory = mock(InventoryService.class); OrderService service = new OrderService(mockInventory); Order order = new Order(List.of(new Item("SKU-42", 2))); service.placeOrder(order); verify(mockInventory).reserve(order.getItems()); }
الكائنات Java العادية (POJOs): لا ترث beans Spring أي فئة إطار ولا تُنفّذ أي واجهة إطار. إنها فئات Java عادية. هذا مبدأ تصميم متعمّد — يبقى نموذج مجالك نظيفًا وقابلًا للنقل.

كيف يندمج Spring في تطوير Java الحديث

اللحق Jakarta EE (خليفة J2EE) بفارق كبير — يُقدّم CDI نموذجًا موحّدًا لحقن التبعيات، وحاويات EE الحديثة أخفّ بكثير. لم يعد Spring وJakarta EE بالمسافة ذاتها التي كانا عليها.

في الممارسة العملية، لا يزال Spring يهيمن لأسباب عدة:

  • اتساع النظام البيئي — Spring Data وSpring Security وSpring Cloud لا مكافئات مباشرة لها بالنضج ذاته.
  • تجربة المطوّر مع Spring Boot — خدمة جديدة في أقل من خمس دقائق بإعدادات افتراضية جاهزة للإنتاج.
  • جودة المجتمع والتوثيق — المستندات المرجعية والأدلة وتغطية Stack Overflow استثنائية.
  • التبنّي التدريجي — يمكنك إضافة Spring إلى مشروع Java عادي قائم دون إعادة كتابة أي شيء.
Spring 6 / Spring Boot 3 يتطلبان Java 17 أو أحدث ويستخدمان استيرادات jakarta.* (وليس javax.*). إن كنت تطّلع على دروس قديمة تستورد javax.servlet أو javax.persistence، فهي تنطبق على Spring 5 وما قبله. يستخدم كل الكود في هذا البرنامج التعليمي مساحة الاسم الحديثة jakarta.*.

الخلاصة

وُلد Spring من إحباط الاقتران الوثيق وصعوبة الاختبار في J2EE. إجابته الجوهرية كانت بسيطة: دع الإطار يتولى إنشاء الكائنات وربطها، وابقِ فئاتك كائنات Java عادية. كل شيء آخر في نظام Spring البيئي — Boot وSecurity وData وCloud — مبني فوق هذا الأساس. في الدرس القادم ستفحص المبدأ الذي يجعل كل ذلك ممكنًا: قلب التحكم.