إعداد Spring والملفّات الشخصية

نظرة عامة على أساليب التهيئة

18 دقيقة الدرس 1 من 13

نظرة عامة على أساليب التهيئة

دعم Spring منذ نشأته ثلاثة أساليب مختلفة لتهيئة حاوية التطبيق: التهيئة بـ XML، والتهيئة المدفوعة بالتعليقات التوضيحية (Annotations)، والتهيئة المستندة إلى Java. بوصفك مطورًا محترفًا ستصادف الأساليب الثلاثة في قواعد الكود الموجودة، وتحتاج إلى فهم شكل كل أسلوب ومتى يتألق وسبب تقارع المجتمع نحو التهيئة المستندة إلى Java في المشاريع الجديدة التي تعمل بـ Spring 6 و Spring Boot 3.

الأسلوب الأول — التهيئة بـ XML

وُلد Spring مع XML. كان كل Bean وكل اعتمادية وكل قيمة خاصية تُعلَن في ملف أو أكثر من ملفات .xml التي يقرأها Spring عند الإقلاع عبر ClassPathXmlApplicationContext أو ما يماثله. جعل هذا الأسلوب ربط Spring منفصلًا تمامًا عن كود التطبيق، وكان ذلك يُعدّ ميزةً في مطلع الألفية الثالثة حين كانت فكرة عكس التحكم (IoC) جديدة.

<!-- beans.xml (حقبة Spring 2.x) --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="jdbcUrl" value="jdbc:postgresql://localhost/shop"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.pass}"/> </bean> <bean id="orderRepository" class="com.example.OrderRepositoryImpl"> <constructor-arg ref="dataSource"/> </bean> </beans>

ما تخسره مع XML: لا يستطيع المُصرِّف التحقق من أسماء Bean أو مراجع الفئات. خطأ مطبعي مثل class="com.example.OrederRepositoryImpl" لا يُكتشف حتى تنطلق التطبيق. إعادة تسمية فئة تستلزم بحثًا واستبدالًا في XML لا إعادة تسمية في بيئة التطوير. تتسع المطوّلية سلبًا — فالتطبيقات المؤسسية الكبيرة المبنية بهذه الطريقة كانت تتراكم فيها آلاف الأسطر من XML موزعة على عشرات الملفات.

الأسلوب الثاني — التهيئة المدفوعة بالتعليقات التوضيحية

قدّم Spring 2.5 التعليقات @Component و@Service و@Repository و@Controller و@Autowired. مع تفعيل مسح المكوّنات، يكتشف Spring الـ Beans تلقائيًا ويربطها بمجرد العثور على الفئات الموسومة في مسار الفئات. قلّص هذا استخدام XML بشكل ملحوظ.

// يمسح Spring هذه الحزمة ويسجّل الفئة كـ Bean @Repository public class OrderRepositoryImpl implements OrderRepository { private final DataSource dataSource; @Autowired // يحقن Spring الـ DataSource Bean هنا public OrderRepositoryImpl(DataSource dataSource) { this.dataSource = dataSource; } }

لا يزال يلزم وجود ملف XML لتفعيل المسح والإعلان عن Beans البنية التحتية (كـ DataSource) التي لا يستطيع Spring اكتشافها بنفسه:

<!-- ملف XML أخف — لكنه لا يزال موجودًا --> <context:component-scan base-package="com.example"/> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="jdbcUrl" value="jdbc:postgresql://localhost/shop"/> </bean>

قرّبت التعليقات المنطق من الكود لكنها أوجدت مشكلة مختلفة: باتت التهيئة متناثرة. لفهم كيفية ربط مكوّن ما كنت بحاجة إلى التنقل بين ملف الفئة وملف XML وربما ملف خصائص. لم يكن ثمة مكان واحد يمنحك الصورة الكاملة.

الأسلوب الثالث — التهيئة المستندة إلى Java

قدّم Spring 3.0 كلًّا من @Configuration و@Bean، مُزيلًا XML كليًا. فئة التهيئة هي فئة Java عادية موسومة بـ @Configuration؛ وكل طريقة موسومة بـ @Bean تنتج Bean تديره حاوية Spring.

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; @Configuration public class DataConfig { @Bean public DataSource dataSource() { HikariConfig cfg = new HikariConfig(); cfg.setJdbcUrl("jdbc:postgresql://localhost/shop"); cfg.setUsername(System.getenv("DB_USER")); cfg.setPassword(System.getenv("DB_PASS")); return new HikariDataSource(cfg); } @Bean public OrderRepository orderRepository(DataSource dataSource) { // يحقن Spring الـ Bean المُعلَن أعلاه return new OrderRepositoryImpl(dataSource); } }

لتشغيل هذا السياق خارج Spring Boot:

import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class App { public static void main(String[] args) { var ctx = new AnnotationConfigApplicationContext(DataConfig.class); OrderRepository repo = ctx.getBean(OrderRepository.class); // استخدام repo ... ctx.close(); } }
في Spring Boot 3 لن تستدعي AnnotationConfigApplicationContext مباشرةً إلا نادرًا. تُنشئ SpringApplication.run() سياق التطبيق وتديره بنفسها، ماسحةً فئة @SpringBootApplication وجميع فئات @Configuration التي تجدها. الآلية متطابقة — أنت فقط لا تكتب كود الإقلاع بنفسك.

لماذا تُفضَّل التهيئة بـ Java اليوم

لم يكن التحول إلى التهيئة بـ Java مجرد تفضيل أسلوبي، بل يمنح مزايا عملية ملموسة:

  • أمان وقت الترجمة. يتحقق المُصرِّف من أسماء الفئات والطرق وأنواع المعاملات. أي إعادة هيكلة خاطئة تُفشل عملية البناء لا التوظيف.
  • دعم بيئة التطوير (IDE). تعمل ميزات الانتقال إلى التعريف والبحث عن الاستخدامات وإعادة التسمية في فئات التهيئة تمامًا كما تعمل في كود Java العادي. مع XML لم تكن بيئات التطوير توفر سوى دعم جزئي.
  • تعبيرية Java الكاملة. يمكنك استخدام if والحلقات والطرق المصنعية والمبنيّات وفحوصات البيئة وأي بنية Java أخرى داخل طريقة @Bean. لم يكن بإمكان XML التعبير عن المنطق الشرطي دون امتدادات XML خاصة بـ Spring.
  • سهولة الاختبار. فئة التهيئة فئة Java. يمكنك إنشاء نسخة منها في اختبار وحدة واستدعاء طرق @Bean مباشرةً والتحقق من الكائنات المنتجة دون تشغيل سياق Spring كامل.
  • التماسك. تقطن تعريفات الـ Bean المترابطة معًا في فئة واحدة، مما يجعل فهم ربط نظام فرعي أمرًا يسيرًا للوهلة الأولى.
فضّل حقن المُنشئ على حقن الحقل. حتى مع التهيئة بـ Java، قد تميل إلى استخدام @Autowired على حقل داخل فئة خدمة. فضّل حقن المُنشئ عوضًا عن ذلك: فهو يجعل الاعتماديات صريحة ويُبقي الفئات قابلة للاختبار دون سياق Spring ويتوافق مع حقول final. تُزيل أداة @RequiredArgsConstructor من Lombok كل الكود النمطي المتكرر.

هل يمكن المزج بين الأساليب الثلاثة؟

نعم — يدعم Spring مزج الأساليب الثلاثة في تطبيق واحد، وستصادف ذلك في مشاريع حقيقية تُهاجر كودًا قديمًا. يمكن لفئة تهيئة Java استيراد ملف XML عبر @ImportResource("classpath:legacy-beans.xml"). كما يمكن لملف XML تفعيل مسح التهيئة بـ Java عبر <context:annotation-config/>. وتعمل التعليقات على فئات المكوّنات بصرف النظر عمّا إذا كان باقي التطبيق يستخدم XML أو تهيئة Java.

خلط الأساليب يزيد الأعباء المعرفية. حين تستلم قاعدة كود تستخدم الأساليب الثلاثة، ارسم خريطتها أولًا: حدّد أي Beans تأتي من XML وأيها من مسح المكوّنات وأيها من فئات @Configuration. محاولة تتبع اعتمادية دون هذه الخريطة يُفضي إلى ارتباك حول سبب وجود Bean وأين جرى تسجيله.

تهيئة التعليقات مقابل تهيئة Java — التمييز المتبقي

حتى في مشاريع Spring Boot 3 الحديثة، ثمة تقسيم عملي للعمل بين الأسلوبين غير الـ XML:

  • مسح المكوّنات (@Component، @Service، @Repository، @Controller) يُستخدم لفئات التطبيق التي تمتلكها — خدمات الأعمال والمستودعات والمتحكمات. يكتشفها Spring تلقائيًا.
  • تهيئة Java (@Configuration + @Bean) تُستخدم للفئات الخارجية التي لا تستطيع توسيمها بنفسك (مثل HikariDataSource وـ ObjectMapper من Jackson وعملاء AWS SDK) وللـ Beans التي تتطلب منطق بناء غير تافه.

فهم هذا التقسيم هو الأساس لكل ما يأتي في هذا البرنامج التعليمي: متى تترك مسح المكوّنات يؤدي العمل، ومتى تكتب طريقة @Bean صريحة، وكيف تُخرج قيم التهيئة، وكيف تُغيّر السلوك بين البيئات، وكيف تجعل الـ Beans مشروطة. الدرس القادم يتعمق في التهيئة المستندة إلى Java — الأسلوب الذي ستستخدمه أكثر من غيره.