تعليقات Spring التوضيحية: @Component و @Repository و @Service — ما الفرق؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يوجد ثلاثة تعليقات توضيحية في Spring لنفس الغرض؟

\n\n

كل من بدأ العمل مع Spring، عاجلاً أم آجلاً، طرح السؤال التالي: "لماذا نحتاج إلى ثلاثة تعليقات توضيحية مختلفة — @Component و @Repository و @Service — إذا كانت جميعها تسجل ببساطة Bean في السياق؟".

\n\n

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

\n\n

في هذه المقالة، لن نقوم فقط بسرد الاختلافات. سنقوم بتحليل فلسفة Spring، وننظر تحت غطاء المحرك للحاوية، ونوضح كيف يمكن للاستخدام الصحيح للتعليقات التوضيحية أن ينقذ مشروعك من الأخطاء الخفية. هيا بنا!

\n\n

نبذة مختصرة: ما هي التعليقات التوضيحية النمطية؟

\n\n

تنتمي التعليقات التوضيحية الثلاثة جميعها إلى ما يسمى التعليقات التوضيحية النمطية (stereotype annotations). وهي تخبر Spring أن الفئة هي مكون مُدار (Bean) ويجب اكتشافها تلقائياً أثناء مسح classpath.

\n\n

التعليق التوضيحي الأساسي هو @Component. إنه الأساس. @Repository و @Service و @Controller هي أشكال متخصصة من @Component، والتي تضيف دلالات وسلوكاً إضافيين.

\n\n
@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Component // هذه هي النقطة الأساسية!\npublic @interface Service {\n    // ...\n}
\n\n

كما ترى، @Service نفسه مُعلَّق بـ @Component. هذا يعني أن Spring سيعالجها تماماً مثل @Component العادي. ولكن لماذا إذن نعقد الأمور؟

\n\n

@Component — الجندي الشامل

\n\n

@Component هو التعليق التوضيحي الأكثر عمومية. استخدمه عندما لا يناسب فصلك أي فئة من الفئات الأكثر تحديداً.

\n\n

أمثلة نموذجية:

\n
    \n
  • الأدوات المساعدة
  • \n
  • كائنات التهيئة (لا تخلط مع @Configuration)
  • \n
  • أي فئات يجب أن تكون Beans، ولكنها ليست خدمات أو مستودعات أو وحدات تحكم
  • \n
\n\n
import org.springframework.stereotype.Component;\n\n@Component\npublic class EmailValidator {\n\n    public boolean isValid(String email) {\n        return email != null && email.contains("@");\n    }\n}
\n\n

لاحظ: EmailValidator لا ينفذ منطق الأعمال (هذا ليس @Service) ولا يعمل مع قاعدة البيانات (هذا ليس @Repository). لذلك، @Component هو الخيار المثالي.

\n\n

@Repository — حارس البيانات

\n\n

@Repository هو أول تعليق توضيحي متخصص يضيف وظائف حقيقية. بالإضافة إلى تسجيل Bean، فإنه يؤدي مهمتين مهمتين:

\n\n
    \n
  1. اعتراض استثناءات الوصول إلى البيانات. يقوم Spring تلقائياً بتغليف الاستثناءات من DAO (كائن الوصول إلى البيانات) في DataAccessException — التسلسل الهرمي للاستثناءات في Spring.
  2. \n
  3. تحسين قابلية قراءة الكود. أي مطور، عند رؤية @Repository، يفهم فوراً: "أها، هنا يتم العمل مع قاعدة البيانات".
  4. \n
\n\n
import org.springframework.stereotype.Repository;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n@Repository\npublic interface UserRepository extends JpaRepository<User, Long> {\n\n    User findByEmail(String email);\n}
\n\n

هام: إذا كنت تستخدم Spring Data JPA وتورث من JpaRepository، فإن Spring سينشئ Bean وكيلاً بنفسه. التعليق التوضيحي الصريح @Repository ليس إلزامياً، ولكنه موصى به للإشارة الصريحة إلى الغرض.

\n\n

الميزة الرئيسية لـ @Repository هي معترض AOP (PersistenceExceptionTranslationPostProcessor)

المدونات

توصيات الكتب