انتقل إلى المحتوى الرئيسي

الفصل 1: عكس التحكم (IoC)

مقدمة​

مرحبًا! في هذا الفصل، ستفهم المبدأ الأساسي الذي يجعل Spring يعمل.

ما ستتعلمه​

  1. مشكلة الترابط القوي (ولماذا هو سيء)
  2. الحل: عكس التحكم
  3. كيف ينفذ Spring IoC
  4. حاوية Spring ودورها

المدة: 30 دقيقة


المشكلة: الترابط القوي​

الوضع الحقيقي​

تخيل أنك تطور تطبيق تجارة إلكترونية. تحتاج إلى إرسال رسائل بريد إلكتروني للعملاء.

❌ النهج التقليدي (بدون IoC)​

public class OrderService {

// نقوم بإنشاء كائن EmailService مباشرة
private EmailService emailService = new EmailService();

public void processOrder(Order order) {
// منطق العمل
saveOrder(order);

// إرسال بريد إلكتروني للتأكيد
emailService.sendEmail(order.getCustomerEmail(), "تم تأكيد الطلب");
}
}

لماذا هذا مشكلة؟​

المشكلة 1: الترابط القوي​

private EmailService emailService = new EmailService();
// ^^^^^^^^^^^^^^^^
// اعتماد مباشر!

النتيجة:

  • OrderService يعتمد مباشرة على EmailService
  • من المستحيل تغيير التنفيذ بسهولة
  • صعب الاختبار

المشكلة 2: من المستحيل تغيير التنفيذ​

السيناريو: تريد الانتقال من Gmail إلى SendGrid لإرسال الرسائل الإلكترونية.

// يجب تعديل OrderService
public class OrderService {
// قبل
private EmailService emailService = new EmailService();

// بعد - يجب تغيير الكود!
private SendGridEmailService emailService = new SendGridEmailService();
// ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
}

المشكلة: تعديل كود يعمل = خطر حدوث أخطاء!


المشكلة 3: من المستحيل الاختبار​

تريد اختبار OrderService بدون إرسال رسائل بريد إلكتروني حقيقية:

@Test
public void testProcessOrder() {
OrderService service = new OrderService();
Order order = new Order(...);

service.processOrder(order);

// المشكلة: سيتم إرسال بريد إلكتروني حقيقي!
// من المستحيل "محاكاة" EmailService
}

ملخص المشكلة​

OrderService ──────────> EmailService
(اعتماد مباشر)

❌ ترابط قوي
❌ صعب التعديل
❌ صعب الاختبار
❌ كود صلب وهش

الحل: عكس التحكم (IoC)​

المبدأ الأساسي​

"لا تنشئ اعتمادياتك، اطلبها!"

بدلاً من:

private EmailService emailService = new EmailService();  // ❌ أنا أنشئ

افعل:

private EmailService emailService;  // ✅ شخص ما يعطيني إياه

ما هو IoC؟​

عكس التحكم (IoC) = عكس من يتحكم في إنشاء الكائنات

قبل IoC (التحكم العادي)​

OrderService يقول: "أحتاج إلى EmailService"
OrderService يقول: "سأقوم بإنشائه بنفسي باستخدام 'new'"

مع IoC (التحكم المعكوس)​

OrderService يقول: "أحتاج إلى EmailService"
Spring يقول: "لا مشكلة، سأعطيك إياه!"
Spring ينشئ EmailService ويعطيه لـ OrderService

التحكم في الإنشاء معكوس: Spring هو الذي يدير، وليس أنت!


✅ النهج مع IoC (حقن الاعتماديات)​

الكود المحسن​

@Service
public class OrderService {

// لا نقوم بإنشاء الكائن
private final EmailService emailService;

// نطلب الكائن عبر المنشئ
public OrderService(EmailService emailService) {
this.emailService = emailService;
}

public void processOrder(Order order) {
saveOrder(order);
emailService.sendEmail(order.getCustomerEmail(), "تم تأكيد الطلب");
}
}

ما يحدث​


فوائد IoC​

1. ترابط ضعيف​

// OrderService لا يعرف التنفيذ الفعلي
private final EmailService emailService;
// ^^^^^^^^^^^^
// واجهة (تجريد)

يمكنك الحصول على عدة تنفيذات:

public interface EmailService {
void sendEmail(String to, String message);
}

public class GmailEmailService implements EmailService {
// إرسال عبر Gmail
}

public class SendGridEmailService implements EmailService {
// إرسال عبر SendGrid
}

Spring يختار أي واحدة يستخدم وفقًا للتكوين!


2. سهل التعديل​

تغيير التنفيذ بدون لمس OrderService:

// تكوين Spring
@Configuration
public class AppConfig {

@Bean
public EmailService emailService() {
// قبل
// return new GmailEmailService();

// بعد - تغيير في مكان واحد فقط!
return new SendGridEmailService();
}
}

OrderService لا يحتاج إلى التغيير!


3. سهل الاختبار​

@Test
public void testProcessOrder() {
// نقوم بإنشاء "خدمة بريد إلكتروني وهمية" للاختبارات
EmailService fakeEmailService = new EmailService() {
@Override
public void sendEmail(String to, String message) {
System.out.println("تم إرسال بريد إلكتروني محاكى إلى: " + to);
// لا يتم إرسال بريد إلكتروني حقيقي!
}
};

// نقوم بحقن الخدمة الوهمية
OrderService service = new OrderService(fakeEmailService);

Order order = new Order(...);
service.processOrder(order);

// ✅ لا يتم إرسال بريد إلكتروني حقيقي!
}

حاوية Spring (ApplicationContext)​

ما هي الحاوية؟​

حاوية Spring = مدير الكائنات في Spring

مسؤولياتها:

  1. ✅ إنشاء الكائنات (beans)
  2. ✅ تكوينها
  3. ✅ تجميعها (حقن الاعتماديات)
  4. ✅ إدارة دورة حياتها

تشبيه​

فكر في حاوية Spring كـ قائد أوركسترا:

قائد أوركسترا (حاوية Spring)
↓
الموسيقيون (Beans: Controller, Service, Repository)
↓
الأوركسترا تعزف الموسيقى (التطبيق يعمل)

قائد الأوركسترا:

  • ✅ يجند الموسيقيين (ينشئ beans)
  • ✅ يضعهم في المكان المناسب (حقن)
  • ✅ ينسق عملهم (إدارة دورة الحياة)

الحاوية في العمل​

// عند بدء التطبيق
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// هذه السطر يبدأ حاوية Spring
SpringApplication.run(DemoApplication.class, args);
// ^^^
// الحاوية تبدأ هنا!
}
}

ما تفعله الحاوية عند البدء:

1. مسح الفئات مع @Component, @Service, @Repository, @Controller
↓
2. إنشاء الكائنات (beans)
↓
3. حل الاعتماديات
↓
4. حقن الاعتماديات
↓
5. التطبيق جاهز!

تصور الحاوية​

الحاوية تدير جميع الكائنات واعتمادياتها!


مثال كامل​

بدون IoC (الكود القديم)​

public class OrderService {
private EmailService emailService = new EmailService();
private PaymentService paymentService = new PaymentService();
private InventoryService inventoryService = new InventoryService();

public void processOrder(Order order) {
paymentService.charge(order);
inventoryService.reserve(order);
emailService.sendConfirmation(order);
}
}

مشاكل:

  • ❌ 3 اعتماديات تم إنشاؤها باستخدام new
  • ❌ ترابط قوي في كل مكان
  • ❌ من المستحيل الاختبار
  • ❌ صلب وهش

مع IoC (كود Spring)​

@Service
public class OrderService {

// إعلان الاعتماديات (بدون 'new')
private final EmailService emailService;
private final PaymentService paymentService;
private final InventoryService inventoryService;

// حقن عبر المنشئ
public OrderService(
EmailService emailService,
PaymentService paymentService,
InventoryService inventoryService
) {
this.emailService = emailService;
this.paymentService = paymentService;
this.inventoryService = inventoryService;
}

public void processOrder(Order order) {
paymentService.charge(order);
inventoryService.reserve(order);
emailService.sendConfirmation(order);
}
}

فوائد:

  • ✅ 0 استخدام لـ new (Spring يدير كل شيء)
  • ✅ ترابط ضعيف
  • ✅ سهل الاختبار (يمكن حقن الوهميات)
  • ✅ مرن وقابل للصيانة

المفاهيم الأساسية التي يجب تذكرها​

1. عكس التحكم (IoC)​

"Spring يتحكم في إنشاء الكائنات، وليس أنت."

قبل: أنت تنشئ كائناتك باستخدام new
بعد: Spring ينشئ كائناتك ويعطيك إياها


2. حقن الاعتماديات (DI)​

"Spring يحقن (يعطي) الاعتماديات التي تحتاجها."

الآلية: عبر المنشئ، setters، أو مباشرة في الحقول


3. حاوية Spring​

"المدير المركزي الذي ينشئ ويجمع جميع الكائنات."

المسؤوليات:

  • إنشاء beans
  • حل الاعتماديات
  • حقن الاعتماديات
  • إدارة دورة الحياة

ملخص الفصل​

المشكلة​

// ❌ ترابط قوي
private EmailService service = new EmailService();

النتائج:

  • صعب التعديل
  • صعب الاختبار
  • كود صلب

الحل​

// ✅ IoC + حقن الاعتماديات
@Service
public class OrderService {
private final EmailService service;

public OrderService(EmailService service) {
this.service = service;
}
}

فوائد:

  • ترابط ضعيف
  • سهل التعديل
  • سهل الاختبار
  • كود مرن

التشبيه النهائي​

IoC = مطعم

بدون IoC:

أنت: "أنا جائع"
أنت: "سأشتري المكونات"
أنت: "سأطبخ"
أنت: "آكل"

مع IoC:

أنت: "أنا جائع" (إعلان الحاجة)
المطعم: "إليك وجبتك!" (Spring يوفر)
أنت: "آكل" (أنت تستخدم)

أنت لا تنشئ الوجبة، بل تُعطى لك. هذا هو IoC!


التقييم الذاتي​

أجب عن هذه الأسئلة للتحقق من فهمك:

  1. ما هو عكس التحكم؟
  2. ما هي مشكلة الترابط القوي؟
  3. ما هو دور حاوية Spring؟
  4. لماذا يسهل IoC الاختبارات؟

إذا لم تتمكن من الإجابة، أعد قراءة الفصل!


الخطوة التالية​

الآن بعد أن فهمت لماذا يوجد IoC، دعنا ننتقل إلى كيف: حقن الاعتماديات.

➡️ الفصل 2: حقن الاعتماديات

⬅️ العودة إلى الوحدة 5