دورة حياة الـ Bean
دورة حياة الـ Bean
يمرّ كل كائن يديره حاوي Spring بدورة حياة محدّدة المعالم: يُنشأ الكائن أولًا، ثم تُعبَّأ تبعياته، ثم تُشغَّل استدعاءات التهيئة، ثم يخدم الكائنُ التطبيقَ، وأخيرًا تُنظّف الموارد عبر استدعاءات الإتلاف. إن فهمت كل مرحلة، أمكنك التدخّل في اللحظة المناسبة تمامًا — سواء أردتَ فتح مجمّع اتصالات، أو التحقق من الإعدادات، أو تفريغ ذاكرة التخزين المؤقت قبل الإيقاف.
المراحل الأربع في لمحة
- الإنشاء (Instantiation) — يُنشئ الحاوي الكائن الخام باستخدام الدالة البانية (أو factory method).
- تعبئة التبعيات (Dependency Population) — يحقن Spring جميع التبعيات: وسائط الدالة البانية، واستدعاءات الـ setter، وحقن الحقل عبر
@Autowired. - التهيئة (Initialisation) — بعد تعبئة جميع التبعيات، تُشغَّل استدعاءات التهيئة. يمكن لكودك الآن استخدام المتعاونين المحقونين بالكامل.
- الإتلاف (Destruction) — عند إغلاق السياق (إيقاف التطبيق، تفكيك بيئة الاختبار، إلخ)، تُحرِّر استدعاءات الإتلاف الموارد.
null لأن Spring لم تضبطه بعد.
المرحلة الأولى — الإنشاء
ينشئ Spring نسخة الـ bean باستخدام الانعكاس (Reflection). بالنسبة لـ bean مفردة (singleton — الوضع الافتراضي) يحدث هذا مرةً واحدة عند بدء سياق التطبيق. أما بالنسبة لـ bean من نوع prototype فيحدث في كل مرة يُطلَب فيها. في هذه اللحظة يكون الكائن مجرد كائن Java عادي — لم تُضبط له أي تبعيات.
يدمج حقن الدالة البانية المرحلتين 1 و2 في خطوة واحدة، وهو أحد أسباب تفضيله: لن يظهر الكائن أبدًا في حالة تهيئة جزئية.
المرحلة الثانية — تعبئة التبعيات
بعد الإنشاء (في حالة حقن الـ setter أو الحقل)، يفحص Spring تعريف الـ bean ويحلّ كل تبعية من الحاوي، ثم يستدعي الـ setter المناسب أو يكتب مباشرةً في الحقل. هنا تُعالَج @Autowired و@Value و@Inject.
المرحلة الثالثة — التهيئة
بمجرد حقن جميع التبعيات، يستدعي Spring استدعاءات التهيئة بهذا الترتيب:
- التوابع الموسومة بـ
@PostConstruct(الموصى بها) - التابع
afterPropertiesSet()إن كان الـ bean ينفّذInitializingBean - تابع
init-methodمخصص مُعلَن في@Bean(initMethod = "...")
@PostConstruct هو الخيار الأنظف: إنه توصيف Java معياري (jakarta.annotation.PostConstruct) مستقل عن Spring، مما يبقي الفئة محمولة وقابلة للاختبار.
@PostConstruct من أجل: فتح الموارد (مجمّعات الخيوط ومجمّعات الاتصالات)، وتحميل الإعدادات في الذاكرة، والتحقق من ربط التبعيات المطلوبة بصورة صحيحة، أو تعبئة ذاكرات التخزين المؤقت. احرص على سرعة التنفيذ — فـ @PostConstruct البطيء يؤخّر بدء تشغيل السياق.
المرحلة الرابعة — الإتلاف
عند إغلاق ApplicationContext الخاص بـ Spring — عند إيقاف JVM، أو عند استدعاء context.close() في اختبار، أو عند رفع تطبيق ويب — تعمل استدعاءات الإتلاف لجميع beans المفردة بترتيب عكسي للتسجيل:
- التوابع الموسومة بـ
@PreDestroy(الموصى بها) - التابع
destroy()إن كان الـ bean ينفّذDisposableBean - تابع
destroy-methodمخصص مُعلَن في@Bean(destroyMethod = "...")
@PreDestroy أبدًا على bean من نوع prototype. إن كانت الـ bean من نوع prototype تحتجز موارد، فعليك إدارة دورة حياتها يدويًا.
استخدام توابع Init وDestroy مع @Bean
عند دمج فئة خارجية لا تملك صلاحية تعديل مصدرها، استخدم السمتين initMethod وdestroyMethod على @Bean:
close() أو shutdown() بوصفه تابع الإتلاف للـ beans المُعادة من توابع @Bean، لذا كثيرًا ما لا تحتاج إلى تحديد destroyMethod صراحةً. يمكنك تعطيل هذا السلوك بضبط destroyMethod = "".
دورة الحياة الكاملة — مثال شامل واحد
تتعمّد الفئة التالية تمرين جميع المراحل الأربع حتى تتمكن من مراقبة الترتيب في سجلاتك:
الخرج المتوقع في السجل عند بدء التشغيل واستدعاء context.close():
الخلاصة
تمرّ دورة حياة الـ bean في Spring بأربع مراحل متمايزة: الإنشاء (الدالة البانية)، وتعبئة التبعيات (الحقن)، والتهيئة (@PostConstruct ← afterPropertiesSet() ← init مخصص)، والإتلاف (@PreDestroy ← destroy() ← destroy مخصص). عمليًا، الجأ إلى @PostConstruct و@PreDestroy — فهما يُبقيان الـ beans محمولة وسهلة القراءة. استخدم @Bean(initMethod, destroyMethod) عند دمج فئات خارجية. وتذكّر أن الـ beans من نوع prototype لا تشملها إدارة Spring للإتلاف إطلاقًا.