الوحدة 18: أسئلة المقابلة Spring Boot
الأهداف
تُعدك هذه الوحدة لـ المقابلات التقنية في تطوير Java/Spring Boot. الأسئلة منظمة حسب مستوى الصعوبة والموضوع، وتغطي المواضيع الأكثر شيوعًا في المقابلات.
لا تقم بحفظ الإجابات كلمة بكلمة. افهم المفاهيم وكن قادرًا على شرحها بكلماتك الخاصة مع أمثلة ملموسة.
فصول الوحدة
| # | الفصل | المحتوى |
|---|---|---|
| 1 | JPA وقاعدة البيانات | مشكلة N+1، التحميل الكسول/النشط، @Transactional، الترقيم، العلاقات بين الكيانات |
| 2 | تمارين إعادة الهيكلة | عبارات الحراسة، نمط الاستراتيجية، SRP (God Class)، الثوابت السحرية، التركيب مقابل الوراثة |
| 3 | الخوارزميات وهياكل البيانات | HashMap، Stack، LinkedList، البحث الثنائي، Two Sum، FizzBuzz، التباديل |
| 4 | تصميم REST وأنماط التصميم | API REST، Builder، Singleton، Observer مع أحداث Spring |
| 5 | تصحيح الأخطاء ومراجعة الكود | العثور على الأخطاء، مراجعة الكود، تسرب الذاكرة، التزامن، الاستثناءات، روائح الكود |
| 6 | فخاخ Java الأساسية | == مقابل .equals()، hashCode()، final، static، String غير قابل للتغيير، Optional، المرور بالقيمة |
| 7 | مجموعات Java | List.of() مقابل new ArrayList<>()، HashMap، HashSet، Stream API، أمان الخيوط، التكرار |
| 8 | "ما هو...؟" — 30 مفهومًا | DTO، MVC، API REST، CRUD، POJO، Bean، IoC، ORM/JPA، Maven، Docker، JWT، CORS، Lombok، Record... |
المستوى 1: أسئلة أساسية
س1. ما هو Spring Boot وكيف يختلف عن Spring Framework؟
الإجابة المتوقعة:
Spring Boot هو إطار عمل مبني فوق Spring Framework الذي يبسط التكوين والنشر. الفروقات الرئيسية:
| الجانب | Spring Framework | Spring Boot |
|---|---|---|
| التكوين | يدوي (XML أو Java) | التكوين التلقائي |
| الخادم | خادم خارجي مطلوب | خادم مدمج (Tomcat) |
| التبعيات | تُدار بشكل فردي | Starters مُعدة مسبقًا |
| البدء | معقد | main() + @SpringBootApplication |
Spring Boot لا يستبدل Spring، بل يجعله أسهل في الاستخدام.
س2. ماذا تفعل التعليمة @SpringBootApplication؟
الإجابة المتوقعة:
هي تعليمة ميتا تجمع بين ثلاث تعليمات:
@SpringBootConfiguration: تشير إلى فئة تكوين Spring@EnableAutoConfiguration: تُفعل التكوين التلقائي بناءً على تبعيات classpath@ComponentScan: تفحص الحزمة الحالية وحزمها الفرعية للعثور على beans
س3. ما هو حقن التبعيات (DI)؟
الإجابة المتوقعة:
حقن التبعيات هو نمط تصميم حيث تُوفر تبعيات كائن من الخارج بدلاً من إنشائها بواسطة الكائن نفسه.
// بدون DI (ترابط قوي)
public class OrderService {
private UserRepository repo = new UserRepository(); // ينشئ تبعيته الخاصة
}
// مع DI (ترابط ضعيف)
public class OrderService {
private final UserRepository repo;
public OrderService(UserRepository repo) { // تُحقن من الخارج
this.repo = repo;
}
}
الفوائد: القابلية للاختبار، فك الترابط، المرونة.
س4. ما الفرق بين @Controller و @RestController؟
الإجابة المتوقعة:
@Controllerيعيد أسماء العرض (قوالب HTML). لإعادة JSON، يجب إضافة@ResponseBodyعلى كل طريقة.@RestController=@Controller+@ResponseBody. كل طريقة تعيد مباشرة بيانات مسلسلة في JSON.
س5. ما هي النطاقات المختلفة للـ bean في Spring؟
الإجابة المتوقعة:
| النطاق | الوصف |
|---|---|
| singleton | مثيل واحد لكل حاوية (افتراضي) |
| prototype | مثيل جديد عند كل حقن |
| request | مثيل واحد لكل طلب HTTP |
| session | مثيل واحد لكل جلسة HTTP |
| application | مثيل واحد لكل ServletContext |
س6. ما الفرق بين application.properties و application.yml؟
الإجابة المتوقعة:
نفس الوظيفة، صيغة مختلفة:
# application.properties (مفتاح=قيمة، مسطح)
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
# application.yml (هرمي، أكثر قابلية للقراءة)
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
YAML أكثر قابلية للقراءة للتكوينات المتداخلة، لكن احذر من المسافات البادئة.
س7. ما هو Starter Spring Boot؟
الإجابة المتوقعة:
الـ starter هو مجموعة من التبعيات المُعدة مسبقًا لاستخدام معين:
spring-boot-starter-web: تطبيق ويب (Tomcat، Spring MVC، Jackson)spring-boot-starter-data-jpa: الاستمرارية (Hibernate، Spring Data JPA)spring-boot-starter-security: الأمان (Spring Security)spring-boot-starter-test: الاختبارات (JUnit، Mockito، MockMvc)
تجنب إدارة التوافقات بين الإصدارات يدويًا.
المستوى 2: أسئلة متوسطة
س8. اشرح بنية الطبقات لتطبيق Spring Boot.
الإجابة المتوقعة:
عميل HTTP
↓
┌─────────────────┐
│ Controller │ يستقبل الطلبات، يتحقق منها، يعيد الردود
├─────────────────┤
│ Service │ المنطق التجاري، القواعد التجارية، التنسيق
├─────────────────┤
│ Repository │ الوصول إلى البيانات (CRUD، استعلامات قاعدة البيانات)
├─────────────────┤
│ Database │ PostgreSQL، MySQL، H2...
└─────────────────┘
كل طبقة تتواصل فقط مع الطبقة التي تحتها مباشرة. الـ Controller لا يصل أبدًا مباشرة إلى الـ Repository.
س9. ما الفرق بين JpaRepository، CrudRepository و PagingAndSortingRepository؟
الإجابة المتوقعة:
JpaRepository (الأكثر شمولاً)
↑ يرث من
PagingAndSortingRepository (الترقيم + الفرز)
↑ يرث من
CrudRepository (CRUD الأساسي)
↑ يرث من
Repository (علامة)
- CrudRepository :
save(),findById(),findAll(),deleteById() - PagingAndSortingRepository : يضيف
findAll(Pageable),findAll(Sort) - JpaRepository : يضيف
flush(),saveAndFlush(),deleteInBatch(), يعيدListبدلاً منIterable
في الممارسة، نستخدم دائمًا تقريبًا JpaRepository.
س10. كيف تعمل التكوين التلقائي في Spring Boot؟
الإجابة المتوقعة:
يفحص Spring Boot classpath عند البدء ويكوّن تلقائيًا الـ beans اللازمة:
- إذا كان
spring-boot-starter-data-jpaفي classpath وتم تكوينDataSource→ يكوّن تلقائيًا Hibernate، EntityManager، إلخ. - إذا كان
spring-boot-starter-webفي classpath → يكوّن تلقائيًا Tomcat، Jackson، DispatcherServlet - تحدد التعليمة
@ConditionalOn...ما إذا كان التكوين التلقائي ينطبق
يمكننا دائمًا تجاوز الـ beans المكونة تلقائيًا باستخدام @Bean الخاصة بنا.
س11. ما هي Spring Profiles وما فائدتها؟
الإجابة المتوقعة:
تسمح الـ profiles بتحميل تكوينات مختلفة حسب البيئة:
# application-dev.yml
spring:
datasource:
url: jdbc:h2:mem:devdb
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://prod-server:5432/mydb
التفعيل: --spring.profiles.active=prod أو SPRING_PROFILES_ACTIVE=prod
يمكننا أيضًا تقييد الـ beans باستخدام @Profile("dev").
س12. اشرح الفرق بين @Transactional في القراءة والكتابة.
الإجابة المتوقعة:
@Transactional(readOnly = true) // قراءة: تحسين Hibernate (لا يوجد فحص قذر)
public List<User> findAll() { ... }
@Transactional // كتابة: commit إذا نجح، rollback إذا حدث استثناء
public User create(UserDto dto) { ... }
أفضل ممارسة: وضع @Transactional(readOnly = true) على مستوى فئة الخدمة، و@Transactional على طرق الكتابة فقط.
س13. كيف ندير الاستثناءات في API REST Spring Boot؟
الإجابة المتوقعة:
ثلاثة نهج، من الأكثر محلية إلى الأكثر شمولاً:
@ExceptionHandlerفي وحدة تحكم (نطاق محلي)@RestControllerAdviceمع@ExceptionHandler(نطاق شامل)@ResponseStatusعلى استثناء مخصص
أفضل ممارسة هي @RestControllerAdvice الشامل الذي يركز كل إدارة الأخطاء.
س14. ما هو مشكلة N+1 في JPA وكيف نحلها؟
الإجابة المتوقعة:
تحدث مشكلة N+1 عندما نقوم بتحميل كيان وJPA ينفذ N استعلامات إضافية لتحميل العلاقات:
1 استعلام لتحميل 100 قسم
+ 100 استعلام لتحميل الموظفين لكل قسم
= 101 استعلام بدلاً من 1 أو 2
الحلول:
JOIN FETCHفي JPQL :@Query("SELECT d FROM Department d JOIN FETCH d.employees")@EntityGraph:@EntityGraph(attributePaths = {"employees"})@BatchSize: تحميل العلاقات على دفعات
س15. كيف نؤمن API REST باستخدام JWT؟
الإجابة المتوقعة:
تدفق JWT:
1. يرسل العميل اسم المستخدم/كلمة المرور → POST /api/auth/login
2. يتحقق الخادم من بيانات الاعتماد
3. إذا كان صحيحًا → يولد JWT موقعة ويعيدها
4. يخزن العميل JWT
5. لكل طلب → Authorization: Bearer <token>
6. JwtAuthenticationFilter يستخرج ويحقق من صحة الرمز
7. إذا كان صحيحًا → يصادق المستخدم في SecurityContext
المكونات الرئيسية: JwtService (التوليد/التحقق)، JwtAuthenticationFilter (المرشح)، SecurityConfig (التكوين).
المستوى 3: أسئلة متقدمة
س16. اشرح نمط IoC (Inversion of Control) في Spring.
الإجابة المتوقعة:
IoC يعكس تدفق التحكم: بدلاً من أن يقوم الكود بإنشاء تبعياته، يقوم حاوية Spring بإنشائها وحقنها.
حاوية Spring (ApplicationContext) مسؤولة عن:
- إنشاء الكائنات (beans)
- تكوين الكائنات
- تجميع التبعيات
- إدارة دورة الحياة
حقن التبعيات (DI) هو الآلية الرئيسية لـ IoC في Spring.
س17. ما الفرق بين @Component، @Service، @Repository و @Controller؟
الإجابة المتوقعة:
تقنيًا، الأربعة هم @Component. الفرق هو دلالي (الدور في البنية):
@Component: bean عام@Service: منطق تجاري@Repository: الوصول إلى البيانات + الترجمة التلقائية لاستثناءات SQL إلى استثناءات Spring@Controller: إدارة طلبات الويب
استخدام التعليمة الصحيحة يساعد في القراءة ويسمح بمعالجات محددة (مثل ترجمة الاستثناءات لـ @Repository).
س18. كيف ننفذ الترقيم في Spring Data JPA؟
الإجابة المتوقعة:
// Repository
public interface UserRepository extends JpaRepository<User, Long> {
Page<User> findByRole(Role role, Pageable pageable);
}
// Controller
@GetMapping("/users")
public Page<User> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "name") String sortBy) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
return userRepository.findAll(pageable);
}
الـ Page<T> المعاد يحتوي على: المحتوى، رقم الصفحة، الحجم، إجمالي العناصر، عدد الصفحات.
س19. اشرح استراتيجيات الانتشار المختلفة لـ @Transactional.
الإجابة المتوقعة:
| الانتشار | السلوك |
|---|---|
REQUIRED (افتراضي) | ينضم إلى المعاملة الحالية أو ينشئ واحدة جديدة |
REQUIRES_NEW | ينشئ دائمًا معاملة جديدة (يعلق الحالية) |
SUPPORTS | ينضم إذا كانت موجودة، وإلا ينفذ بدون معاملة |
NOT_SUPPORTED | ينفذ دائمًا بدون معاملة (يعلق الحالية) |
MANDATORY | معاملة موجودة مطلوبة، وإلا استثناء |
NEVER | لا معاملة، وإلا استثناء |
NESTED | معاملة متداخلة (نقطة حفظ) |
حالة استخدام شائعة لـ REQUIRES_NEW : سجل التدقيق الذي يجب أن يستمر حتى إذا فشلت المعاملة الرئيسية.
س20. كيف نحسن أداء تطبيق Spring Boot؟
الإجابة المتوقعة:
-
JPA/Hibernate:
- تجنب مشكلة N+1 (JOIN FETCH، EntityGraph)
- استخدام
@Transactional(readOnly = true)للقراءات - الإسقاطات DTO بدلاً من الكيانات الكاملة
- الترقيم بشكل منهجي
-
التخزين المؤقت:
@Cacheableمع Spring Cache (Redis، Caffeine)- التخزين المؤقت HTTP (ETag، Cache-Control)
-
التكوين:
- تجميع الاتصالات (HikariCP مُكون بشكل صحيح)
- ضغط GZIP
- ملفات تعريف محسنة للإنتاج
-
البنية:
- العمليات غير المتزامنة (
@Async) - فهرسة قاعدة البيانات المناسبة
- التحميل الكسول للعلاقات
- العمليات غير المتزامنة (
س21. ما هو Spring Actuator وما هي النقاط النهائية المفيدة التي يوفرها؟
الإجابة المتوقعة:
يوفر Spring Actuator نقاطًا نهائية للمراقبة والإدارة:
| النقطة النهائية | الوصف |
|---|---|
/actuator/health | حالة التطبيق (UP/DOWN) |
/actuator/info | معلومات عن التطبيق |
/actuator/metrics | مقاييس (الذاكرة، وحدة المعالجة المركزية، الطلبات) |
/actuator/env | متغيرات البيئة |
/actuator/beans | قائمة بجميع الـ beans |
/actuator/mappings | جميع النقاط النهائية REST |
/actuator/loggers | تكوين المسجلات |
/actuator/prometheus | مقاييس بتنسيق Prometheus |
في الإنتاج، يجب تأمين هذه النقاط النهائية وعدم كشف سوى /health و /info علنًا.
س22. اشرح دورة حياة bean في Spring.
الإجابة المتوقعة:
1. الإنشاء (المُنشئ)
2. حقن التبعيات (@Autowired)
3. واجهات Aware (BeanNameAware، ApplicationContextAware...)
4. BeanPostProcessor.postProcessBeforeInitialization()
5. @PostConstruct
6. InitializingBean.afterPropertiesSet()
7. طريقة init مخصصة
8. BeanPostProcessor.postProcessAfterInitialization()
9. ══════ bean جاهز للاستخدام ══════
10. @PreDestroy
11. DisposableBean.destroy()
12. طريقة destroy مخصصة
في الممارسة، نستخدم بشكل أساسي @PostConstruct و @PreDestroy.
س23. كيف ننفذ نمط CQRS مبسط مع Spring Boot؟
الإجابة المتوقعة:
CQRS (Command Query Responsibility Segregation) يفصل بين عمليات القراءة والكتابة:
// Command (كتابة)
@Service
@Transactional
public class UserCommandService {
public User create(CreateUserCommand cmd) { ... }
public void update(UpdateUserCommand cmd) { ... }
public void delete(Long id) { ... }
}
// Query (قراءة)
@Service
@Transactional(readOnly = true)
public class UserQueryService {
public UserDto findById(Long id) { ... }
public Page<UserDto> findAll(Pageable page) { ... }
}
يسمح ذلك بتحسين القراءات والكتابات بشكل منفصل (مثل: الإسقاطات DTO للقراءات، التحقق المعقد للكتابات).
أسئلة سلوكية / سيناريوهات
س24. يجب عليك تصميم API REST لنظام تجارة إلكترونية. ما هي النقاط النهائية التي تنشئها؟
الإجابة المتوقعة:
المنتجات:
GET /api/products → قائمة مرقمة
GET /api/products/{id} → تفاصيل منتج
POST /api/products → إنشاء (ADMIN)
PUT /api/products/{id} → تعديل (ADMIN)
DELETE /api/products/{id} → حذف (ADMIN)
الطلبات:
POST /api/orders → تقديم طلب
GET /api/orders → طلباتي
GET /api/orders/{id} → تفاصيل طلب
PATCH /api/orders/{id} → تعديل الحالة (ADMIN)
المصادقة:
POST /api/auth/register → تسجيل
POST /api/auth/login → تسجيل الدخول (يعيد JWT)
POST /api/auth/refresh → تحديث الرمز
السلة:
GET /api/cart → سلتي
POST /api/cart/items → إضافة إلى السلة
DELETE /api/cart/items/{id} → إزالة من السلة
س25. تطبيق Spring Boot الخاص بك بطيء في الإنتاج. كيف تشخص المشكلة؟
الإجابة المتوقعة:
- Actuator metrics : تحقق من
/actuator/metrics/http.server.requestsلتحديد النقاط النهائية البطيئة - السجلات : تفعيل
logging.level.org.hibernate.SQL=DEBUGلرؤية استعلامات SQL - مشكلة N+1 : تحقق من عدد الاستعلامات باستخدام
spring.jpa.show-sql=true - تجميع الاتصالات : تحقق من مقاييس HikariCP (
hikaricp.connections.active) - التحليل : VisualVM أو JFR (Java Flight Recorder)
- فهرسة قاعدة البيانات : تحليل الاستعلامات البطيئة باستخدام
EXPLAIN ANALYZE - الذاكرة : تحقق من جامع القمامة وحجم الكومة
قائمة التحقق من التحضير
قبل مقابلتك، تأكد من قدرتك على:
- شرح IoC و DI مع مثال ملموس
- وصف بنية الطبقات لتطبيق Spring Boot
- كتابة CRUD كامل (Controller → Service → Repository)
- شرح JWT وتدفق المصادقة
- التحدث عن مشاريعك الشخصية في Spring Boot
- وصف كيفية إدارة الاستثناءات
- شرح الفرق بين التعليمات الرئيسية
- التحدث عن Docker و CI/CD مع Spring Boot
- معرفة أساسيات الترقيم والفرز
- معرفة كيفية تشخيص مشاكل الأداء