باستخدام الشرطي في الربيع

في هذه المقالة ، أريد وصف شرح توضيحي مفيد للغاية ، وغالبًا ما يستخدم واجهة الشرط .


إن سياق الربيع عبارة عن حاوية ضخمة تحتوي على فاصوليا مختلفة ، سواء في الربيع نفسه أو العرف. تريد دائمًا الحصول على أدوات إدارة مرنة لهذه الحديقة. تم إنشاء التعليق التوضيحيConditional فقط لهذا الغرض.


الطريقة الأكثر شيوعًا لإدارة سياق الربيع هي من خلال ملفات التعريف. إنها تسمح لك بالتحكم بسرعة وسهولة في إنتاج الحبوب. لكن في بعض الأحيان ، قد تكون هناك حاجة إلى مزيد من الضبط.


على سبيل المثال ، أثناء الاختبار ، تنشأ مشكلة: يتطلب اختبار الوحدة على جهاز المطور صندوقًا من النوع X لعمله ، وعند إجراء الاختبار نفسه على خادم الإنشاء ، يلزم وجود Y-bin ، وتكون Z-bin مطلوبة في الإنتاج. تقدم Conditional طريقة بسيطة وسهلة في هذه الحالة القرار. كما يحدث في كثير من الأحيان عند العمل في فرق غير متزامنة ، ليس لدى شخص ما وقت لإكمال مراجعته بحلول الموعد النهائي ، وتكون وظيفتك جاهزة بالفعل. من الضروري التكيف مع هذه الشروط وتغيير السلوك. وهذا يعني ، إضافة القدرة على تغيير سياق التطبيق دون إعادة ترجمة ، على سبيل المثال ، تغيير معلمة واحدة فقط في التكوين.


النظر في هذا الشرح في مزيد من التفاصيل. فوق كل صندوق في الكود المصدري ، يمكننا إضافة Conditional وسوف يتحقق الربيع تلقائيًا من الشروط المحددة في هذا التعليق التوضيحي عند إنشائه.


في الوثائق الرسمية ، يتم التصريح بهذا الشكل:


@Target(value={TYPE,METHOD}) @Retention(value=RUNTIME) @Documented public @interface Conditional 

في الوقت نفسه ، تحتاج إلى نقل مجموعة من الشروط إلى ذلك:


 Class<? extends Condition>[] 

حيث Conditional هو الواجهة الوظيفية التي تحتوي على الطريقة


 boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) 

دعونا نتحقق من كيفية عملها في الواقع ، باستخدام مثال حي. يحتوي تطبيقنا على واجهات في شكل صابون / خدمات الراحة ، وفي شكل JMS. لكن المسؤولين لم يكن لديهم الوقت لإعداد البنية التحتية المناسبة في الوقت المناسب - لا يمكننا استخدام JMS.
هناك بعض إعدادات java لـ JMS في مشروعنا:


 @Configuration public class JmsConfig { ... } 

يجد الربيع هذا التكوين ويبدأ في التهيئة. بعد ذلك ، يتم سحب جميع الحبوب التابعة الأخرى ، على سبيل المثال ، القراءة من قائمة الانتظار. لتعطيل إنشاء هذا التكوين ، سنستخدم التعليق التوضيحي المشروط المشروط - ConditioanalOnProperty


 @ConditionalOnProperty( value="project.mq.enabled", matchIfMissing = false) @Configuration public class JmsConfig { ... } 

نعلم هنا سياق المنشئ أننا سننشئ هذا التكوين فقط إذا كانت هناك قيمة موجبة للمشروع project.mq.enabled الثابت في ملف الإعدادات.
الآن ، دعنا ننتقل إلى الفول المعتمد ووضع علامة عليها مع تعليق توضيحي ConditioanalOnBean ، مما سيمنع الربيع من إنشاء حبوب تعتمد على التكوين الخاص بنا.


 @ConditionalOnBean(JmsConfig.class) @Component public class JmsConsumer { ... } 

وبالتالي ، باستخدام معلمة واحدة ، يمكننا تعطيل مكونات التطبيق التي لا نحتاج إليها ، ثم إضافتها إلى السياق عن طريق تغيير التكوين.


إلى جانب الإطار ، يوجد عدد كبير من التعليقات التوضيحية الجاهزة التي تغطي 99 ٪ من احتياجات المطور (والتي سيتم وصفها لاحقًا في المقالة). ولكن ماذا لو كنت بحاجة للتعامل مع بعض المواقف المحددة. للقيام بذلك ، يمكنك إضافة المنطق المخصص الخاص بك إلى الربيع.


افترض أن لدينا بعض bean - SuperDBLogger ، والتي نريد إنشاؤها فقط إذا كان هناك تعليق توضيحي Loggable على أي من صناديقنا . كيف سيبدو في الكود:


 @Component @ConditionalOnLoggableAnnotation public class SuperDBLogger 

ضع في اعتبارك كيف يعمل التعليق التوضيحي ConditionalOnLoggableAnnotation :


 @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Conditional(OnLoggableAnnotation.class) public @interface ConditionalOnLoggableAnnotation { } 

لا نحتاج إلى أي معلمات أخرى ، فلننتقل الآن إلى المنطق نفسه - محتويات فئة OnLoggableAnnotation . في ذلك ، نعيد تعريف طريقة التطابق ، التي ننفذ بها البحث عن الفاصوليا المميزة في الحزمة الخاصة بنا.


 public class OnLoggableAnnotation implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ClassPathScanner scanner = new ClassPathScanner(); scanner.addIncludeFilter(new AnnotationTypeFilter(Loggable.class)); Set<BeanDefinition> bd = scanner.findInPackage("ru.habr.mybeans"); if (!bd.isEmpty()) return true; return false; } } 

وبالتالي ، أنشأنا قاعدة والتي بموجبها الربيع الآن بإنشاء SuperDBLogger . بالنسبة لمحبي SpringBoot ، قام مبتكرو إطار العمل بإنشاء SpringBootCondition ، وهو خليفة لشرط . يختلف في توقيع الطريقة المعاد تعريفها:


 public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata); 

هذا هو ، بالإضافة إلى الإجابة ، نحتاج إلى صندوق أم لا ، يمكنك إضافة رسالة ، والتي يمكن رؤيتها بعد ذلك في سجلات الربيع ، مع إدراك سبب إنشاء الصندوق أو عدمه.


يمكن دمج شروط متعددة لإنشاء شروط أكثر تعقيدًا ؛ توفر هذه الآليات الفئات AnyNestedCondition و AllNestedConditions و NoneNestedConditions . لنفترض أننا نريد إنشاء شرطين بحيث يتم تنفيذ حبة لدينا عند تنفيذ أحدهما. للقيام بذلك ، قم بإنشاء الفصل الخاص بك وارثه من AnyNestedCondition .


 public class AnnotationAndPropertyCondition extends AnyNestedCondition { public AnnotationAndPropertyCondition() { super(REGISTER_BEAN); } @ConditionalOnProperty(value = "db.superLogger") static class Condition1 {} @ConditionalOnLoggableAnnotation static class Condition2 {} } 

لا يحتاج الفصل إلى وضع علامات توضيحية إضافية مع وجود أي تعليقات توضيحية ، حيث سيجدها الربيع نفسه ويعالجها بشكل صحيح. يحتاج المستخدم فقط للإشارة في أي مرحلة من التكوين يتم استيفاء الشروط: ConfigurationPhase .REGISTER_BEAN - عند إنشاء فاصوليا منتظمة ، ConfigurationPhase .PARSE_CONFIGURATION - عند العمل مع التكوينات (أي ، للحاويات المميزة بتعليمة توضيحية توضيحية @ ).


وبالمثل ، بالنسبة للفئات AllNestedConditions و NoneNestedConditions - الأولى تراقب وفاء جميع الشروط ، والثانية - أنه لم يتم استيفاء أي شرط.


أيضًا ، من أجل التحقق من العديد من الشروط ، يمكنك تمرير العديد من الفئات بشروط إلى Conditional . على سبيل المثال ، Conditional ({OnLoggableAnnotation.class، AnnotationAndPropertyCondition.class}) . يجب أن يعود كلاهما صحيحًا حتى يتم استيفاء الشرط ويتم إنشاء الحبة.


كما ذكرت أعلاه ، هناك بالفعل العديد من الحلول الجاهزة مع الربيع ، والتي يتم عرضها في الجدول أدناه.


ملخصوصف
ConditionalOnBeanتتحقق الحالة إذا كان الحبة المرغوبة موجودة في BeanFactory.
ConditionalOnClassيتم استيفاء الحالة إذا كانت الفئة المطلوبة موجودة في classpath.
ConditionalOnCloudPlatformيتحقق الشرط عندما تكون منصة معينة نشطة.
ConditionalOnExpressionالشرط صحيح عندما يُرجع تعبير SpEL قيمة موجبة.
ConditionalOnJavaيتحقق الشرط عندما يتم تشغيل التطبيق مع إصدار محدد من JVM.
ConditionalOnJndiيتم استيفاء الشرط فقط في حالة توفر مورد معين من خلال JNDI.
ConditionalOnMissingBeanتتحقق الحالة إذا كانت الحبة المرغوبة مفقودة في BeanFactory.
ConditionalOnMissingClassالشرط صحيح إذا كانت الفئة المطلوبة غير موجودة في classpath.
ConditionalOnNotWebApplicationالشرط صحيح إذا كان سياق التطبيق ليس سياق ويب.
ConditionalOnPropertyيتم استيفاء الشرط إذا تم تحديد المعلمات الضرورية في ملف الإعدادات.
ConditionalOnResourceيتم استيفاء الشرط إذا كان المورد المطلوب موجودًا في classpath.
ConditionalOnSingleCandidateيتم استيفاء الشرط إذا كان فاصوليا الفئة المحددة موجودًا بالفعل في BeanFactory وهو الوحيد.
ConditionalOnWebApplicationالشرط صحيح إذا كان سياق التطبيق هو سياق ويب.

يمكن تطبيقها جميعًا معًا على تعريف واحد للحاوية.


وبالتالي ، فإن Conditional هي أداة قوية لتهيئة السياق ، مما يجعل التطبيقات أكثر مرونة. لكن تجدر الإشارة إلى حقيقة أنك تحتاج إلى استخدام هذا التعليق التوضيحي بعناية ، لأن سلوك السياق يصبح غير واضح كما هو الحال عند استخدام ملفات التعريف - مع وجود عدد كبير من الصناديق المكونة ، يمكنك الخلط بسرعة. يُنصح بتوثيق وتسجيل تطبيقه بعناية في مشروعك ، وإلا فإن دعم الكود سوف يسبب صعوبات.

Source: https://habr.com/ru/post/ar462541/


All Articles