الـ Beans الشرطية (@Conditional)
الـ Beans الشرطية (@Conditional)
يتسم حاوي IoC في Spring بمرونة استثنائية: يمكنك توجيهه لتسجيل bean معين فقط عند استيفاء شرط محدد أثناء بدء التشغيل — مثل قيمة خاصية معينة، أو بيئة تشغيل بعينها، أو وجود أو غياب فئة على مسار الفئات (classpath). هذه هي الآلية التي يقوم عليها نظام الضبط التلقائي الشهير في Spring Boot، وفهمها يُتيح لك كتابة فئات تهيئة تتكيّف بذكاء مع مختلف البيئات دون الحاجة إلى كتابة جملة if واحدة داخل كود الأعمال.
التجريد الجوهري: Condition و @Conditional
كل فحص شرطي للـ bean مبني على واجهة واحدة: org.springframework.context.annotation.Condition، التي تحتوي على تابع وحيد:
يمنحك ConditionContext وصولًا إلى BeanDefinitionRegistry وConfigurableListableBeanFactory وEnvironment وResourceLoader وClassLoader. هذا يعني أن الشرط المخصص يستطيع فحص أي شيء يعرفه Spring وقت بدء التشغيل.
تربط الشرط بأي تابع @Bean أو فئة @Configuration باستخدام @Conditional(YourCondition.class). إذا أعاد matches() القيمة false، يُتجاهل تعريف الـ bean صامتًا — لا خطأ ولا عنصر بديل.
الشروط الجاهزة في Spring Boot
يأتي Spring Boot مزوّدًا بمجموعة غنية من الشروط الجاهزة في الحزمة org.springframework.boot.autoconfigure.condition، وهي اللبنات الأساسية لكل مبدئ ضبط تلقائي:
@ConditionalOnProperty— يسجّل الـ bean فقط عندما تمتلك خاصية معينة قيمة محددة.@ConditionalOnClass/@ConditionalOnMissingClass— بناءً على وجود أو غياب فئة على مسار الفئات.@ConditionalOnBean/@ConditionalOnMissingBean— بناءً على ما إذا كان bean آخر مسجّلًا بالفعل أم لا.@ConditionalOnExpression— يُقيَّم مقابل تعبير SpEL.@ConditionalOnWebApplication/@ConditionalOnNotWebApplication— بناءً على نوع التطبيق.@ConditionalOnCloudPlatform— يطابق منصة نشر بعينها كـ Kubernetes أو Cloud Foundry.
مثال عملي: Bean مرتبط بعلامة ميزة
افترض أن خدمة الإشعارات ينبغي أن ترسل بريدًا إلكترونيًا حقيقيًا في الإنتاج، بينما تكتفي بالكتابة إلى الـ console في بيئة التطوير المحلية. استخدم @ConditionalOnProperty للتبديل بين التنفيذين بناءً على علامة:
matchIfMissing = true على الـ bean الاحتياطي. اجمعه مع @ConditionalOnMissingBean لضمان تسجيل تنفيذ واحد بالضبط حتى حين تغيب الخاصية. يظهر هذا النمط في كل أنحاء ضبط Spring Boot التلقائي.
@ConditionalOnMissingBean: نمط القابلية للتوسعة
أقوى نمط في ضبط Spring Boot التلقائي هو التراجع: قدّم إعدادًا افتراضيًا معقولًا، لكن دع مطوّر التطبيق يتجاوزه ببساطة بتعريف bean خاص به من النوع ذاته.
إذا أعلن التطبيق عن CacheManager خاص به — مثل واحد مدعوم بـ Redis — يتراجع الضبط التلقائي صامتًا. لا حاجة للإقصاء الصريح ولا لعلامة خاصية. يأخذ الـ bean الصريح في التطبيق الأولوية لأن Spring يعالج فئات @Configuration الخاصة بالتطبيق قبل الضبط التلقائي.
كتابة شرط مخصص
حين لا تناسب أي حاشية جاهزة احتياجك، نفّذ واجهة Condition مباشرةً. إليك شرطًا يُنشّط bean فقط عند تشغيل التطبيق على نظام Linux:
لإمكانية إعادة الاستخدام عبر المشاريع، لفّ الشرط في حاشية مركّبة (meta-annotation):
الآن يمكن لأي تابع @Bean أو فئة @Configuration الاكتفاء بالحاشية @ConditionalOnLinux.
@ConditionalOnExpression للمنطق الديناميكي
حين يُعبَّر الشرط بأفضل صورة كصيغة بوليانية على الخصائص، استخدم SpEL:
matches(). الشرط البطيء يُؤخّر كل عملية بدء تشغيل.
الترتيب وتسلسل التقييم
حين يفحص شرط ما وجود bean آخر (@ConditionalOnBean)، يُصبح الترتيب مهمًا. إذا كانت فئة التهيئة B تحتاج إلى التسجيل بعد الفئة A لترى beans الأخيرة، استخدم @AutoConfigureAfter في حالة الضبط التلقائي، أو @DependsOn للترتيب الصريح في كود التطبيق. بدون ترتيب، تصبح النتيجة غير محددة.
لفئات @Configuration العادية التي تتحكم فيها، فضّل @ConditionalOnMissingBean على @ConditionalOnBean لأنك تستطيع التفكير فيه دون القلق بشأن ترتيب التقييم: الشرط يعني أساسًا "إذا لم يسجّل أحد هذا النوع، سأقوم بذلك."
المقايضات وأفضل الممارسات
- فضّل الشروط المبنية على الخصائص على تلك المبنية على الفئات في كود التطبيق — يسهل تجاوزها في الاختبارات بتعيين الخصائص.
- تجنّب تكديس شروط كثيرة على bean واحد. إذا احتجت إلى ثلاثة شروط متحققة معًا، استخرج فئة
@Configurationمخصصة وطبّق الشروط عليها ليُقرأ كسياسة متماسكة. - وثّق الشروط غير الواضحة بتعليق يشرح ما يجب أن يكون صحيحًا حتى يُسجَّل الـ bean. المطورون المستقبليون — وأنت أيضًا — سيشكرونك.
- اختبر الـ beans الشرطية صراحةً. استخدم
ApplicationContextRunnerفي اختبارات الوحدة للتحقق من الـ beans التي تُسجَّل في كل مزيج من الشروط دون تشغيل خادم كامل.
الخلاصة
تمنح الـ beans الشرطية حاوي Spring القدرة على الضبط الذاتي بناءً على بيئة التشغيل. واجهة Condition هي نقطة التوسع الوحيدة؛ وكل حاشيات الضبط التلقائي في Spring Boot — @ConditionalOnProperty و@ConditionalOnMissingBean و@ConditionalOnClass وسائرها — هي تنفيذات قابلة للتركيب وإعادة الاستخدام لتلك الواجهة الواحدة. اكتب شروطًا مخصصة حين لا تناسب أي حاشية جاهزة، لفّها في meta-annotations لإعادة الاستخدام، واختبر كل مسار شرطي باستخدام ApplicationContextRunner لإبقاء تهيئتك موثوقة في جميع البيئات.