الفصل 1: عكس التحكم (IoC)
مقدمة
مرحبًا! في هذا الفصل، ستفهم المبدأ الأساسي الذي يجعل Spring يعمل.
ما ستتعلمه
- مشكلة الترابط القوي (ولماذا هو سيء)
- الحل: عكس التحكم
- كيف ينفذ Spring IoC
- حاوية 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
مسؤولياتها:
- ✅ إنشاء الكائنات (beans)
- ✅ تكوينها
- ✅ تجميعها (حقن الاعتماديات)
- ✅ إدارة دورة حياتها
تشبيه
فكر في حاوية 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!
التقييم الذاتي
أجب عن هذه الأسئلة للتحقق من فهمك:
- ما هو عكس التحكم؟
- ما هي مشكلة الترابط القوي؟
- ما هو دور حاوية Spring؟
- لماذا يسهل IoC الاختبارات؟
إذا لم تتمكن من الإجابة، أعد قراءة الفصل!
الخطوة التالية
الآن بعد أن فهمت لماذا يوجد IoC، دعنا ننتقل إلى كيف: حقن الاعتماديات.