أنواع النصائح (Advice Types)
أنواع النصائح (Advice Types)
في Spring AOP، النصيحة (Advice) هي الإجراء الذي ينفّذه الجانب (Aspect) عند نقطة انضمام (Join Point) معينة. يمنحك Spring خمسة تعليقات توضيحية مميزة للنصائح، لكلٍّ منها علاقة مختلفة بتنفيذ الأسلوب المستهدف. اختيار النوع الصحيح ليس مسألة أسلوب — فلكل نوع ضمانات محددة وقدرات محددة ومقايضات تؤثر على الصحة والأداء والقابلية للصيانة.
جميع الأنواع الخمسة موجودة في الحزمة org.aspectj.lang.annotation وتعمل مع Spring 6 / Spring Boot 3 باستخدام مساحة الأسماء jakarta.*.
@Before — التنفيذ قبل الأسلوب
تُنفَّذ نصيحة @Before قبل استدعاء الأسلوب المستهدف. لا يمكنها إيقاف التنفيذ (إلا برمي استثناء) ولا يمكنها رؤية القيمة المُعادة لأن الأسلوب لم يُنفَّذ بعد.
الاستخدامات الشائعة: فحوصات التحكم في الوصول، التحقق من المدخلات، التحقق من الشروط المسبقة، تسجيل الأحداث قبل وقوع الاستدعاء.
@Before دائمًا قبل جسم الأسلوب. إذا رمت استثناءً، لن يُستدعى الأسلوب المستهدف أبدًا وسيُمرّر Spring الاستثناء إلى المُستدعي. هذا ما يجعلها الخطّاف (hook) المناسب لمنطق التحكم في البوابات.
@After — التنفيذ بعد الأسلوب (Finally)
تعمل نصيحة @After بعد اكتمال الأسلوب — سواء أعاد قيمة بشكل طبيعي أم رمى استثناءً. فكّر فيها كمكافئ الجانب لكتلة finally. لا يمكنها الوصول إلى القيمة المُعادة ولا يمكنها إخفاء الاستثناء أو استبداله.
الاستخدامات الشائعة: تحرير الموارد، مسح حالة الـ Thread المحلية، سجلات "نهاية الاستدعاء" في المراجعات.
@AfterReturning و@AfterThrowing بدلًا من ذلك — فهما يمنحانك هذا التمييز.
@AfterReturning — التنفيذ بعد الإعادة الطبيعية
تُطلق @AfterReturning فقط عندما يكتمل الأسلوب المستهدف دون رمي استثناء. قوتها الكبرى: يمكنك ربط القيمة المُعادة الفعلية وفحصها أو تسجيلها. لا يمكنك استبدال القيمة المُعادة من هذا النوع من النصائح.
يمكنك تضييق نوع المعامل المربوط. إذا كتبت Object savedUser فإنه يطابق أي نوع إعادة. إذا كتبت User savedUser، سيطبّق Spring النصيحة فقط عندما تكون القيمة المُعادة متوافقة مع User.
@AfterReturning هي أنظف مكان لملء ذاكرة التخزين المؤقت بعد قراءة ناجحة من قاعدة البيانات. الأسلوب نُفِّذ وتم بنجاح والنتيجة في يدك الآن — دون أي بنية try/catch في طبقة الخدمة.
@AfterThrowing — التنفيذ عند رمي استثناء
تُطلق @AfterThrowing فقط عندما يرمي الأسلوب المستهدف استثناءً يتجاوزه. يمكنك ربط الاستثناء وتسجيله وتنبيه أنظمة المراقبة أو إثرائه — لكن الاستثناء لا يزال ينتشر ما لم ترمِ استثناءً مختلفًا.
كما في @AfterReturning، يمكنك تقييد نوع الاستثناء. الإعلان عن RuntimeException ex يعني أن الاستثناءات المتحقق منها (checked exceptions) تمر دون تشغيل هذه النصيحة. الإعلان عن Throwable ex يصطاد كل شيء.
@Around — التحكم الكامل في التنفيذ
تُعدّ @Around أقوى نوع من النصائح. فهي تُحيط باستدعاء الأسلوب بالكامل: أنت تقرر ما إذا كنت ستستدعي الأسلوب المستهدف ومتى، ويمكنك تعديل الوسائط قبل استدعائه، وتعديل القيمة المُعادة أو استبدالها بعد عودته. هذه القوة تأتي بمسؤولية — إذا نسيت استدعاء proceed()، لن يُنفَّذ الأسلوب المستهدف أبدًا.
pjp.proceed(). قد يكون نوع الإعادة للأسلوب void (في هذه الحالة تكون القيمة null وإهمالها مقبول)، لكن لجميع الأنواع الأخرى ينتظر المُستدعي تلك القيمة. نسيان تعليمة الإعادة يُترجَم بلا أخطاء لكنه يُنتج أخطاء null صامتة في وقت التشغيل.
ترتيب التنفيذ عندما تنطبق نصائح متعددة
عندما تتطابق عدة نصائح مع نفس نقطة الانضمام، يستدعيها Spring بترتيب محدد حول مكدس الاستدعاء:
@Around(قبلproceed())@Before- تنفيذ الأسلوب المستهدف
@AfterReturningأو@AfterThrowing(أيهما ينطبق)@After@Around(بعد عودةproceed())
عندما تنطبق نصيحتان من نفس النوع في جانبين مختلفين على نفس نقطة الانضمام، يمكنك التحكم في ترتيبهما النسبي باستخدام @Order(n) على فئة الجانب — الرقم الأصغر يعمل في الخارج (أول في الدخول، آخر في الخروج).
اختيار النوع الصحيح من النصائح
- تحتاج إلى بوابة أو تحقق قبل التنفيذ؟ استخدم
@Before. - تحتاج إلى تنظيف مضمون بصرف النظر عن النتيجة؟ استخدم
@After. - تحتاج إلى القيمة المُعادة للتسجيل أو التخزين المؤقت أو التفاعل مع النجاح؟ استخدم
@AfterReturning. - تحتاج إلى اكتشاف استثناء معين وتسجيله أو إثرائه؟ استخدم
@AfterThrowing. - تحتاج إلى تعديل الوسائط أو إخفاء الاستثناءات أو استبدال القيمة المُعادة؟ استخدم
@Around.
يُفضَّل استخدام النوع الأقل قوةً الذي يلبّي متطلباتك. @Around قادرة على كل شيء، لكن استخدامها لمجرد التسجيل البسيط يُعيّم النية ويُدخل خطر ابتلاع الاستثناءات أو القيم المُعادة عن طريق الخطأ. احتفظ بها للمخاوف المشتركة التي تحتاج حقًا إلى تحكم كامل: التخزين المؤقت، والمحاولة مجددًا، والمعاملات، وقواطع الدوائر.
الخلاصة
تُشكّل الأنواع الخمسة من النصائح في Spring AOP طيفًا من الحد الأدنى من المسؤولية (@Before، @After) إلى التحكم الكامل (@Around). لكل نوع عقد واضح: ما الذي يراه، ومتى يعمل، وما الذي يمكنه تغييره. مطابقة النوع الصحيح لمتطلباتك تجعل كود الجانب مقروءًا، وتمنع الأخطاء الدقيقة، وتوصل النية للمطوّر التالي. في الدروس التالية ستضع هذا موضع التطبيق مع @Around وواجهة ProceedingJoinPoint، ثم ستبني جوانب تسجيل وأمن حقيقية.