حاوية حقن التبعية (Dependency Injection) لجافا: ما هي ولماذا نحتاجها؟
\n\nفي تطوير جافا الحديث، أحد المبادئ الأساسية للتصميم هو حقن التبعية (DI) — وهو نمط يحصل فيه الكائن على تبعياته من الخارج، بدلاً من إنشائها بنفسه. لأتمتة هذه العملية، تُستخدم حاويات حقن التبعية — وهي مكتبات تدير دورة حياة الكائنات وعلاقاتها.
\n\nحاوية DI (وتسمى أيضًا حاوية عكس التحكم (IoC)) تتولى إنشاء مكونات التطبيق وتهيئتها وربطها. وهذا يسمح بـ:
\n\n- \n
- تقليل الترابط بين الكود (loose coupling) \n
- تبسيط الاختبار (استبدال التبعيات بسهولة بكائنات وهمية) \n
- زيادة إمكانية إعادة استخدام المكونات \n
- إدارة التهيئة بشكل مركزي \n
كيف تعمل حاوية DI؟
\n\nالمهمة الرئيسية للحاوية هي ربط الواجهات بتطبيقاتها. تتضمن العملية عادةً ثلاث مراحل:
\n\n- \n
- تسجيل التبعيات — تتعرف الحاوية على الفئات والواجهات المتاحة \n
- حل التبعيات — عند إنشاء كائن، تقوم الحاوية بتحليل المُنشئ أو الحقول الخاصة به \n
- الحقن — تقوم الحاوية بإنشاء نسخ من التبعيات وتمريرها إلى الكائن الهدف \n
لنلقِ نظرة على مثال بسيط بدون حاوية:
\n\npublic class UserService {\n private UserRepository repository;\n\n public UserService() {\n // ارتباط صارم — إنشاء التبعية يدويًا\n this.repository = new UserRepositoryImpl();\n }\n}\n\nباستخدام حاوية DI (على سبيل المثال مع Spring):
\n\n@Service\npublic class UserService {\n private final UserRepository repository;\n\n // الحقن عبر المُنشئ\n @Autowired\n public UserService(UserRepository repository) {\n this.repository = repository;\n }\n}\n\nستقوم الحاوية بإنشاء نسخة من UserRepositoryImpl وتمريرها إلى المُنشئ.
حاويات DI الشائعة لجافا
\n\nتوجد عدة حلول ناضجة في سوق جافا. دعنا نستعرض أهمها:
\n\n1. Spring Framework / Spring Boot
\nأشهر حاوية DI. تستخدم التعليقات التوضيحية (@Component, @Service, @Repository) أو تهيئة XML. تدعم:
- \n
- المسح التلقائي للحزم (component scanning) \n
- الملفات الشخصية والتبعيات الشرطية \n
- إدارة دورة حياة الحبوب (singleton, prototype وغيرها) \n
- AOP (البرمجة الموجهة نحو الجوانب) \n
@Configuration\npublic class AppConfig {\n @Bean\n public UserRepository userRepository() {\n return new UserRepositoryImpl();\n }\n\n @Bean\n public UserService userService() {\n return new UserService(userRepository());\n }\n}\n\n2. Google Guice
\nحاوية DI خفيفة وسريعة من Google. تستخدم الوحدات النمطية والتعليق التوضيحي @Inject.
public class MyModule extends AbstractModule {\n @Override\n protected void configure() {\n bind(UserRepository.class).to(UserRepositoryImpl.class);\n }\n}\n\npublic class Main {\n public static void main(String[] args) {\n Injector injector = Guice.createInjector(new MyModule());\n UserService service = injector.getInstance(UserService.class);\n }\n}\n\n3. Dagger 2
\nيُولد الكود في مرحلة الترجمة، مما يعطي أداءً أقصى. يُستخدم غالبًا في تطوير Android.
\n@Component\npublic interface AppComponent {\n UserService getUserService();\n}\n\n@Module\npublic class AppModule {\n @Provides\n UserRepository provideUserRepository() {\n return new UserRepositoryImpl();\n }\n}\n\n// الاستخدام\nAppCompon