@Value ولغة تعبيرات Spring (SpEL)
@Value ولغة تعبيرات Spring (SpEL)
تخزّن ملفات الخصائص ومتغيرات البيئة إعدادات تطبيقك الخارجية: عناوين URL لقواعد البيانات وقيم المهلة الزمنية وأعلام الميزات وعشرات الإعدادات الأخرى التي تختلف بين بيئات التطوير والاختبار والإنتاج. تُعدّ @Value التعليقَ الأساسي الذي يستخدمه Spring لحقن هذه القيم الخارجية مباشرةً في الـ beans. علاوةً على ذلك، يأتي Spring مزوّدًا بمحرك تعبيرات صغير لكن قوي — يُعرف بـ لغة تعبيرات Spring (SpEL) — يُتيح لك حساب القيم وقت الحقن بدلًا من نسخ السلسلة النصية الخام فحسب.
حقن @Value الأساسي
أبسط صور @Value تسحب خاصية من application.properties (أو application.yml) باستخدام عنصر نائب للخاصية محاط بـ ${...}.
يُجري Spring تحويل الأنواع تلقائيًا: تصبح القيمة النصية "3" في ملف الخصائص عددًا صحيحًا int، و"5000" تصبح long، و"false" تصبح boolean. يعمل هذا مع جميع الأنواع الأولية وأنواعها المغلّفة وعدد من أنواع القيم الشائعة.
القيم الافتراضية
إذا كانت الخاصية مفقودة ولم يُقدَّم أي افتراضي، يرمي Spring استثناء BeanCreationException عند بدء التشغيل — إخفاق سريع لا قيمة null صامتة. يمكنك تقديم قيمة احتياطية باستخدام صيغة النقطتين داخل العنصر النائب:
حقن القوائم والمصفوفات
يمكن حقن قيمة خاصية مفصولة بفواصل مباشرةً في مصفوفة أو List:
ConversionService المدمج في Spring. ينطبق هذا على المصفوفات وList<T> حيث يمكن لـ Spring تحويل سلسلة نصية مفردة إلى النوع T. للهياكل المعقدة (الخرائط والكائنات المتداخلة) فضّل @ConfigurationProperties على @Value.
مقدمة إلى SpEL — #{...}
عندما تحتاج إلى أكثر من قيمة خاصية خام، يمكنك تضمين تعبير SpEL داخل #{...}. يُقيَّم SpEL في وقت التشغيل بواسطة حاوية Spring ويستطيع الإشارة إلى beans أخرى واستدعاء الدوال وإجراء العمليات الحسابية والوصول إلى خصائص النظام.
الإشارة إلى beans أخرى في SpEL
يستطيع SpEL الوصول إلى beans أخرى مُدارة بواسطة Spring باسمها، مستدعيًا الدوال أو قارئًا الخصائص:
يعتمد اسم الـ bean في SpEL افتراضيًا على اسم الفئة البسيطة بحرف أول صغير ما لم تُحدد اسمًا صريحًا باستخدام @Component("appConfig").
مزج ${...} و#{...}
يمكنك تداخل عناصر نائبة للخصائص داخل تعبيرات SpEL لدمج الإعدادات الخارجية مع الحساب في وقت التشغيل:
@Value أطول من سطر واحد أو يتطلب شروطًا متعددة، فهذا المنطق ينتمي إلى دالة @PostConstruct أو فئة إعداد مخصصة، لا إلى تعليق توضيحي. تعبيرات SpEL المعقدة يصعب اختبارها، ومستحيل التحقق منها وقت الترجمة، وعسيرة التصحيح.
خصائص النظام ومتغيرات البيئة
يُعرّض SpEL كائنَين ضمنيَّين: systemProperties (خصائص نظام JVM من أعلام -D) وsystemEnvironment (متغيرات بيئة نظام التشغيل). يمكنك الوصول إلى أيٍّ منهما مباشرةً:
في Spring Boot يكون استخدام ${MY_ENV_VAR} (عنصر نائب للخاصية) أبسط دائمًا تقريبًا، لأن Boot يُعيّن متغيرات البيئة بالفعل إلى تجريد Environment الخاص به. احتفظ بصيغة systemEnvironment في SpEL للحالات التي تحتاج فيها إلى دمجها مع عمليات SpEL أخرى.
حقن معاملات المُنشئ والدالة
لا تقتصر @Value على الحقول. يمكنك تعليق معاملات المُنشئ ومعاملات الدالة، مما يجعل الـ bean أسهل في اختبار الوحدة دون سياق Spring:
مع حقن المُنشئ يمكنك ببساطة كتابة new PaymentService("test-key", 500) في اختبار وحدة — لا حاجة لسياق تطبيق، ولا سحر انعكاس، ولا إطار محاكاة مطلوب للإعداد نفسه.
@Value مقابل @ConfigurationProperties
معرفة متى تستخدم كلًّا منهما يتجنب رائحة معمارية شائعة:
- @Value — خاصية أو خاصيتان متفرقتان تنتميان إلى بادئات مختلفة؛ وصول سريع إلى قيم محسوبة أو بيئية عبر SpEL؛ الحالات التي تكون فيها فئة ربط قوية النوع مبالغةً في الأمر.
- @ConfigurationProperties — مجموعة متماسكة من الخصائص ذات الصلة التي تشترك في بادئة مشتركة (مثل
app.mail.*). تمنحك POJO مكتوبة بأنواع محددة وإكمال تلقائي في IDE والتحقق من JSR-303 عند بدء التشغيل وقابلية اختبار أفضل.
@Value باعتبارها الاستثناء لا القاعدة. لأي ميزة تحتوي على أكثر من عنصرين أو ثلاثة من مفاتيح الضبط، أنشئ سجل أو فئة @ConfigurationProperties. احتفظ بـ @Value لحقن الخاصية الواحدة وبـ SpEL للحالات التي تحتاج فيها إلى حساب وقت التشغيل.
الخلاصة
تحقن @Value("${property}") الإعدادات الخارجية في الـ beans مع تحويل تلقائي للأنواع وقيم افتراضية اختيارية. تضمّن @Value("#{expression}") تعبير SpEL يُقيَّم عند بدء تشغيل الحاوية، ممنوحًا إياك الوصول إلى beans أخرى والعمليات الحسابية والشرطية وخصائص النظام. يتكامل الصيغتان: يمكنك تداخل عناصر نائبة ${} داخل تعبيرات #{}. فضّل حقن معاملات المُنشئ على حقن الحقول لتحسين قابلية الاختبار، وانتقل إلى @ConfigurationProperties حين تنمو مجموعة الخصائص ذات الصلة إلى ما هو أكثر من حفنة من القيم.