| # | القسم |
|---|---|
| 1 | ما التبعية؟ |
| 2 | التصريح بتبعية |
| 3 | النطاقات (scopes) |
| 4 | المستودعات (repositories) |
| 5 | الحل الانتقالي |
| 6 | التشخيص والاستبعاد |
| 7 | اختبار — إدارة التبعيات |
| 8 | تطبيق عملي — إضافة تبعيات |
| 9 | الخلاصة |
التبعية مكتبة خارجية يحتاجها مشروعك للتجميع أو التشغيل. بدل إعادة كتابة الشفرة (تحليل JSON، الوصول إلى قاعدة بيانات، اختبارات…)، نعيد استخدام مكتبات مجرَّبة.
يدير Maven هذه التبعيات تلقائياً: تصرّح بها في pom.xml، فينزّلها Maven ويضعها على الـ classpath.
| بلا Maven | مع Maven |
|---|---|
تنزيل كل .jar يدوياً | التصريح بثلاثة أسطر في pom.xml |
| إدارة الـ classpath يدوياً | يبنيه Maven تلقائياً |
| إيجاد مكتبات متوافقة | حل انتقالي تلقائي |
تُعرَّف التبعية أيضاً بإحداثيات GAV (
groupId:artifactId:version)، تماماً كمشروعك. هكذا يعرف Maven ماذا ينزّل.
تُصرَّح التبعيات في الكتلة <dependencies> من pom.xml. كل تبعية وسم <dependency> بإحداثيات GAV.
<dependencies>
<!-- مكتبة Gson من Google لمعالجة JSON -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>لإيجاد الإحداثيات الصحيحة لمكتبة، نراجع Maven Central (search.maven.org)، الذي يوفّر كتلة XML جاهزة للنسخ.
# بعد إضافة تبعية، نطلق التنزيل
mvn compile
# أو التنزيل صراحة دون تجميع
mvn dependency:resolve| العنصر | الدور |
|---|---|
<groupId> | المنظمة التي تنشر المكتبة |
<artifactId> | اسم المكتبة |
<version> | الإصدار المطلوب |
يضع Maven المكتبات في تخزين
~/.m2/repository. مكتبة نُزّلت لا تُنزَّل ثانية: لذلك البناءات التالية سريعة.
تمرين مصغّر — صرّح بتبعية Gson (com.google.code.gson:gson:2.10.1) في كتلة <dependency>.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>النطاق (scope) لتبعية يبيّن متى وأين تكون متاحة: عند التجميع، أو الاختبارات، أو التشغيل، أو يوفّرها البيئة. نحدّده بـ <scope>.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope> <!-- متاحة للاختبارات فقط -->
</dependency>| النطاق | متاحة عند التجميع | متاحة عند الاختبارات | متاحة عند التشغيل | مضمَّنة في الأثر |
|---|---|---|---|---|
compile (افتراضي) | نعم | نعم | نعم | نعم |
test | لا | نعم | لا | لا |
provided | نعم | نعم | لا (يوفرها الخادم) | لا |
runtime | لا | نعم | نعم | نعم |
أمثلة ملموسة :
| المكتبة | النطاق النموذجي | لماذا |
|---|---|---|
| JUnit | test | مفيدة فقط لتشغيل الاختبارات |
| API Servlet | provided | الخادم (Tomcat) يوفّرها أصلاً |
| مشغّل JDBC | runtime | مطلوب عند التشغيل، لا عند التجميع |
| Gson | compile | مستخدمة في كل الشفرة |
وضع JUnit في
compileبدلtestخطأ شائع: يضمّن مكتبة الاختبار بلا داعٍ في المخرج النهائي. اختر دائماً النطاق الأضيق المناسب.
تمرين مصغّر — صرّح بتبعية JUnit Jupiter (5.10.2) بنطاق اختبار في pom.xml.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>ينزّل Maven التبعيات من مستودعات (repositories). هناك ثلاثة مستويات :
| نوع المستودع | الوصف |
|---|---|
| المستودع المحلي | تخزين على جهازك: ~/.m2/repository |
| Maven Central | المستودع العام العالمي، المصدر الافتراضي |
| مستودع خاص | خادم شركة (Nexus، Artifactory) للمكتبات الداخلية |
لإضافة مستودع خاص، نصرّح به في pom.xml :
<repositories>
<repository>
<id>nexus-entreprise</id>
<url>https://nexus.monentreprise.com/repository/maven-public/</url>
</repository>
</repositories># فرض تحديث التبعيات من المستودعات
mvn clean install -U
# إفراغ تخزين مكتبة لفرض إعادة تنزيلها
# (حذف يدوي للمجلد الموافق في ~/.m2)| الحالة | المستودع المستخدم |
|---|---|
| مكتبة عامة مفتوحة المصدر | Maven Central |
| مكتبة داخلية للشركة | مستودع خاص (Nexus/Artifactory) |
| مكتبة نُزّلت مسبقاً | التخزين المحلي ~/.m2 |
تستخدم الشركات غالباً مستودعاً خاصاً كـ مرآة لـ Maven Central: يسرّع التنزيلات ويسمح بالتحكم في المكتبات المسموحة.
قد تعتمد تبعية نفسها على مكتبات أخرى: هذه التبعيات الانتقالية. ينزّلها Maven تلقائياً — لا تحتاج إلى سردها.
تصرّح بـ تبعية واحدة، ويحل Maven عشرات :
<!-- تصريح واحد... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.5</version>
</dependency>
<!-- ...يجلب تلقائياً spring-web و jackson و tomcat وغيرها -->لعرض الشجرة كاملة :
# يعرض شجرة التبعيات (مباشرة + انتقالية)
mvn dependency:treeخرج نموذجي :
com.exemple:mon-app:jar:1.0.0
+- org.springframework.boot:spring-boot-starter-web:jar:3.2.5:compile
| +- org.springframework:spring-web:jar:6.1.6:compile
| +- com.fasterxml.jackson.core:jackson-databind:jar:2.15.4:compile
| \- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.20:compileعندما يجلب مساران إصدارين مختلفين للمكتبة نفسها، يطبّق Maven قاعدة «الأقرب في الشجرة يفوز» (nearest wins): الإصدار الأقرب إلى مشروعك هو الذي يُعتمد.
الحل الانتقالي من أقوى ميزات Maven: تصرّح بنواياك على مستوى عالٍ، ويجمع Maven أحجية التبعيات نيابة عنك.
تمرين مصغّر — اكتب الأمر الذي يعرض شجرة التبعيات الكاملة (مباشرة وانتقالية).
mvn dependency:treeأحياناً تطرح تبعية انتقالية مشكلة (تعارض إصدار، مكتبة غير مرغوبة). يوفّر Maven أدوات للتشخيص والتصحيح.
لـ استبعاد تبعية انتقالية غير مرغوبة :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.5</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>أوامر تشخيص مفيدة :
| الأمر | الدور |
|---|---|
mvn dependency:tree | يعرض شجرة التبعيات الكاملة |
mvn dependency:analyze | يكتشف التبعيات غير المستخدمة أو الناقصة |
mvn dependency:resolve | ينزّل كل التبعيات |
# تحديد التبعيات المصرَّح بها وغير المستخدمة،
# وتلك المستخدمة وغير المصرَّح بها
mvn dependency:analyzeقبل استبعاد أي شيء، شغّل
mvn dependency:treeلفهم من أين تأتي التبعية المشكلة. لا نستبعد أبداً على عمى.
تمرين مصغّر — اكتب الأمر الذي يحدد التبعيات المصرَّح بها وغير المستخدمة (والعكس).
mvn dependency:analyzeالسؤال 1: أين يخزّن Maven التبعيات المنزَّلة؟
a) في target/
b) في ~/.m2/repository
c) في src/main/resources
d) على خادم الويب
الإجابة: b) — المستودع المحلي ~/.m2/repository يعمل تخزيناً: مكتبة نُزّلت لا تُنزَّل ثانية.
السؤال 2: أي نطاق يناسب JUnit، مكتبة تُستخدم للاختبارات فقط؟
a) compile
b) runtime
c) test
d) provided
الإجابة: c) — يجعل النطاق test التبعية متاحة للاختبارات فقط ويستبعدها من المخرج النهائي.
السؤال 3: ما التبعيات الانتقالية؟
a) تبعيات يجب سردها يدوياً
b) تبعيات تبعياتك، يحلها Maven تلقائياً
c) تبعيات مؤقتة
d) تبعيات اختبار
الإجابة: b) — تبعية مصرَّح بها تجلب تبعياتها؛ ينزّلها Maven تلقائياً.
السؤال 4: أي أمر يعرض شجرة التبعيات الكاملة؟
a) mvn list
b) mvn dependency:tree
c) mvn show-deps
d) mvn package
الإجابة: b) — يعرض mvn dependency:tree التبعيات المباشرة والانتقالية، مفيداً لتشخيص التعارضات.
السؤال 5: أي نطاق تختار لـ API Servlet التي يوفّرها خادم Tomcat؟
a) compile
b) test
c) provided
d) runtime
الإجابة: c) — provided: المكتبة لازمة للتجميع، لكن بيئة التشغيل (الخادم) توفّرها أصلاً.
في مشروع قائم، أضف تبعيتين: Gson (com.google.code.gson:gson:2.10.1) بنطاق compile لمعالجة JSON، و JUnit Jupiter (org.junit.jupiter:junit-jupiter:5.10.2) بنطاق test. ثم تحقق من شجرة التبعيات.
<dependencies> المتوقعة<dependencies>
<!-- Gson: مستخدمة في كل الشفرة (نطاق compile افتراضي) -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<!-- JUnit: الاختبارات فقط -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>التحقق :
# تنزيل وعرض شجرة التبعيات
mvn dependency:treeالنتيجة المتوقعة :
com.exemple:mon-app:jar:1.0.0-SNAPSHOT
+- com.google.code.gson:gson:jar:2.10.1:compile
\- org.junit.jupiter:junit-jupiter:jar:5.10.2:test
+- org.junit.jupiter:junit-jupiter-api:jar:5.10.2:test
+- org.junit.jupiter:junit-jupiter-params:jar:5.10.2:test
\- org.junit.jupiter:junit-jupiter-engine:jar:5.10.2:testلاحظ أن
junit-jupiterيجلب تلقائياً-apiو-paramsو-engine: هذه تبعياته الانتقالية. صرّحت بسطر واحد، وحل Maven الباقي.
<dependencies>؛ ينزّلها Maven ويخزّنها في ~/.m2.compile، test، provided، runtime) تتحكم في متى تكون التبعية متاحة.~/.m2)، Maven Central (عام)، خاص (Nexus/Artifactory).mvn dependency:tree بفحصها.الدرس 04 — دورة الحياة والمراحل: فهم المراحل (compile، test، package، install، deploy) التي تنسّق البناء.
جميع الحقوق محفوظة. يُحظَر نسخ هذه الدورة أو نشرها أو استخدامها أو تكييفها، كلياً أو جزئياً، دون إذن كتابي مسبق من الدكتور هيثم رحومة.
دورة من إعداد الدكتور هيثم رحومة — تطوير ونشر حلول البيانات