404 Not Found

404 Not Found


nginx

تطبيق Spring Boot الأول الخاص بك

تعليق @SpringBootApplication وحده كافٍ لتشغيل التطبيق بالكامل—سحر Spring Boot يكمن في الجمع الذكي بين ثلاثة تعليقات.

1. ما ستتعلمه


2. قصة حقيقية عن مشروع جديد

(1) نقطة الألم: يستغرق إعداد المشروع نصف يوم

تذكرت Alice تجربتها مع Spring MVC التقليدي عندما بدأت للتو: إنشاء مشروع يتطلب تهيئة web.xml، وapplicationContext.xml، وspring-mvc.xml، بالإضافة إلى تثبيت Tomcat وتهيئة مصدر بيانات JNDI. مجرد تشغيل المشروع كان يستغرق نصف يوم، ناهيك عن استكشاف أخطاء ترتيب التشغيل ومشاكل تحميل Beans.

(2) حل Spring Boot

Spring Boot يتطلب تعليقاً واحداً وطريقة رئيسية واحدة فقط:

JAVA
@SpringBootApplication
public class OrderFlowApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderFlowApplication.class, args);
    }
}

(3) العوائد

استخدمت Alice مشروع Spring Boot لإنشاء OrderFlow. استغرق الأمر 5 دقائق فقط من الصفر حتى أول استجابة API—بدون XML، بدون حاوية خارجية، وسجلات التشغيل واضحة وسهلة القراءة.


3. تفكيك تعليق @SpringBootApplication

(1) مجموعة من ثلاثة تعليقات

@SpringBootApplication هو تعليق مركب يكافئ استخدام التعليقات الثلاثة التالية في وقت واحد:

100%
graph TB
    A["@SpringBootApplication"] --> B["@SpringBootConfiguration"]
    A --> C["@EnableAutoConfiguration"]
    A --> D["@ComponentScan"]
    B --> B1["يحدد الصنف كمصدر<br/>لتهيئة Bean"]
    C --> C1["يُفعّل التهيئة التلقائية<br/>بناءً على مسار الأصناف"]
    D --> D1["يمسح المكونات<br/>في شجرة الحزمة نفسها"]
التعليق الوظيفة التدوين التقليدي المكافئ
@SpringBootConfiguration تحديد الصنف الحالي كصنف تهيئة @Configuration
@EnableAutoConfiguration تفعيل التهيئة التلقائية @EnableAutoConfiguration
@ComponentScan مسح المكونات <context:component-scan>

(2) قواعد مسح @ComponentScan

@ComponentScan يغطي بشكل افتراضي الحزمة التي تحتوي على صنف التشغيل الرئيسي وجميع حزمها الفرعية.

TEXT
com.orderflow ← الحزمة التي تحتوي على صنف التشغيل الرئيسي
├── OrderFlowApplication.java           ← @SpringBootApplication
├── controller/ ← يتم مسحها بواسطة @ComponentScan
│   └── OrderController.java
├── service/ ← يتم مسحها بواسطة @ComponentScan
│   └── OrderService.java
└── repository/ ← يتم مسحها بواسطة @ComponentScan
    └── OrderRepository.java
com.other ← ⚠️ غير مشمول في المسح!
🔥 خطأ شائع: إذا وضعت المتحكم في حزمة أعلى بمستوى أو بنفس مستوى الحزمة التي تحتوي على صنف التشغيل الرئيسي، فلن يتمكن Spring Boot من مسحه، مما يؤدي إلى خطأ 404.


4. عملية تشغيل SpringApplication.run()

(1) تسلسل التشغيل

عملية تنفيذ SpringApplication.run() هي خط أنابيب مصمم بعناية:

100%
sequenceDiagram
    participant Main as main()
    participant SA as SpringApplication
    participant Ctx as ApplicationContext
    participant Bean as Beans

    Main->>SA: new SpringApplication()
    SA->>SA: استنتاج المصادر الأساسية
    SA->>SA: التحقق من نوع تطبيق الويب
    SA->>SA: تحميل المُهيئات والمستمعين
    Main->>SA: run(args)
    SA->>SA: إنشاء سياق التشغيل الأولي
    SA->>SA: إعداد البيئة
    SA->>SA: طباعة الشعار
    SA->>Ctx: إنشاء ApplicationContext
    SA->>Ctx: إعداد السياق (تسجيل المصادر)
    SA->>Ctx: تحديث السياق
    Ctx->>Bean: إنشاء مثيلات Beans
    Ctx->>Bean: التهيئة التلقائية
    SA->>SA: استدعاء Runners
    SA->>Main: إرجاع ApplicationContext

(2) تحديد نوع تطبيق الويب

Spring Boot يكتشف نوع التطبيق تلقائياً:

الشرط النوع الحاوية المستخدمة
مسار الأصناف يحتوي على spring-webmvc SERVLET Tomcat / Jetty / Undertow
مسار الأصناف يحتوي على spring-webflux وليس spring-webmvc REACTIVE Netty
لا شيء NONE بدون حاويات مدمجة

(1) ▶ مثال: تخصيص تشغيل SpringApplication

JAVA
@SpringBootApplication
public class OrderFlowApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(OrderFlowApplication.class);
        app.setBannerMode(Banner.Mode.CONSOLE);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
    }
}

الناتج:

TEXT
// التنفيذ ناجح

5. تنسيق ملف التهيئة

(1) Properties مقابل YAML

Spring Boot يدعم تنسيقي ملفات تهيئة متكافئين وظيفياً لكنهما يختلفان في الصياغة.

(1) ▶ مثال: كيفية كتابة application.properties

PROPERTIES
server.port=8080
spring.application.name=orderflow-service
spring.datasource.url=jdbc:mysql://localhost:3306/orderflow
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update

الناتج:

TEXT
// التنفيذ ناجح

(2) ▶ مثال: كيفية كتابة application.yml

YAML
server:
  port: 8080

spring:
  application:
    name: orderflow-service
  datasource:
    url: jdbc:mysql://localhost:3306/orderflow
    username: root
    password: secret
  jpa:
    hibernate:
      ddl-auto: update

الناتج:

TEXT
تم تفعيل التهيئة.
البُعد Properties YAML
الهيكل الهرمي مفصول بـ . المسافة البادئة تدل على التسلسل الهرمي
قابلية القراءة أزواج مفتاح-قيمة بسيطة، مسطحة هيكل هرمي واضح، مناسب للتداخل
دعم القوائم list[0]=a - a أكثر بديهية
البادئة المتكررة يجب تكرارها بادئة مشتركة في نفس المستوى
أداء التحليل أسرع أبطأ قليلاً (يتطلب تحليل التسلسل الهرمي)
الأولوية متساوية متساوية (properties لها الأسبقية عند وجود كليهما)
⚠️ ملاحظة: ملفات YAML حساسة جداً للمسافة البادئة؛ يجب استخدام مسافات وليس علامات تبويب، ويجب أن تكون المسافة البادئة متسقة في نفس المستوى.

(2) مرجع سريع لخيارات التهيئة الشائعة

خيار التهيئة القيمة الافتراضية الوصف
server.port 8080 منفذ استماع التطبيق
spring.application.name اسم التطبيق
server.servlet.context-path / المساق السياقي
spring.main.banner-mode console وضع عرض الشعار
spring.jpa.show-sql false طباعة SQL
logging.level.root INFO مستوى السجل العام

6. تخصيص الشعار وسجلات التشغيل

(1) شعار مخصص

ضع شعاراً مخصصاً في src/main/resources/banner.txt ليُعرض تلقائياً عند بدء تشغيل Spring Boot.

(1) ▶ مثال: شعار OrderFlow المخصص

TEXT
  ____              _         ____  __
 / ___| _ __   __ _| |_ ___  / ___||  |  ___  _ __
| |    | '_ \ / _` | __/ _ \ \___ \|  |/ _ \| '_ \
| |___ | | | | (_| | ||  __/  ___) |  | (_) | | | |
 \____||_| |_|\__,_|\__\___| |____/|_|\___/|_| |_|

:: OrderFlow Service ::  v${application.version:1.0.0}
:: Spring Boot ${spring-boot.version} ::

الناتج:

TEXT
التنفيذ ناجح

(2) تفسير سجل التشغيل

TEXT
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_  __ _   \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |  \ \ \ \
 \\/  ___)| |_)| | | | | | || (_| |  / / / /
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.5)

2024-01-15 10:00:01.123  INFO 12345 --- [main] c.o.OrderFlowApplication : Starting OrderFlowApplication
2024-01-15 10:00:03.456  INFO 12345 --- [main] o.s.b.w.e.t.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-01-15 10:00:04.789  INFO 12345 --- [main] o.s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories
2024-01-15 10:00:06.012  INFO 12345 --- [main] c.o.OrderFlowApplication : Started in 5.123 seconds
كلمات السجل الرئيسية المعنى
Starting OrderFlowApplication تشغيل التطبيق
Tomcat initialized with port بدء Tomcat المدمج
Bootstrapping Spring Data JPA التهيئة التلقائية لمستودع JPA
Started in X seconds اكتمل التشغيل، استغرق

7. تشغيل واجهة "Hello OrderFlow" الأولى

(1) ▶ مثال: متحكم Hello OrderFlow

JAVA
package com.orderflow.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class HelloController {

    @GetMapping("/api/hello")
    public Map<String, String> hello() {
        return Map.of(
            "message", "Hello, OrderFlow!",
            "timestamp", java.time.Instant.now().toString()
        );
    }
}

الناتج:

TEXT
HTTP 200 OK
Content-Type: application/json

{"status":"success","data":{}}
💻 الناتج:

TEXT
$ curl http://localhost:8080/api/hello
{"message":"Hello, OrderFlow!","timestamp":"2024-01-15T10:00:00Z"}

(2) ▶ مثال: استخدام @Value لحقن التهيئة

JAVA
@RestController
public class HelloController {

    @Value("${spring.application.name}")
    private String appName;

    @GetMapping("/api/info")
    public Map<String, String> info() {
        return Map.of(
            "application", appName,
            "javaVersion", System.getProperty("java.version")
        );
    }
}

الناتج:

TEXT
// التنفيذ ناجح

8. مثال شامل: تهيئة تشغيل OrderFlow الكاملة

JAVA
// src/main/java/com/orderflow/OrderFlowApplication.java
package com.orderflow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderFlowApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderFlowApplication.class, args);
    }
}

// src/main/java/com/orderflow/controller/OrderFlowController.java
package com.orderflow.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.util.Map;

@RestController
public class OrderFlowController {

    @Value("${spring.application.name:orderflow}")
    private String appName;

    @GetMapping("/api/health")
    public Map<String, Object> health() {
        return Map.of(
            "status", "UP",
            "application", appName,
            "timestamp", Instant.now()
        );
    }
}
YAML
# src/main/resources/application.yml
server:
  port: 8080

spring:
  application:
    name: orderflow-service
💻 الناتج:

TEXT
$ curl http://localhost:8080/api/health
{"status":"UP","application":"orderflow-service","timestamp":"2024-01-15T10:00:00Z"}

❓ أسئلة شائعة

س هل يمكن تطبيق @SpringBootApplication على أي صنف؟
ج تقنياً نعم، لكن يُوصى بشدة بوضعه في الحزمة الجذرية. وذلك لأن @ComponentScan يمسح الحزمة التي تحتوي على الصنف الرئيسي وحزمها الفرعية بشكل افتراضي؛ ووضعه في مكان خاطئ قد يمنع اكتشاف Beans الأخرى.
س هل يمكن التعايش بين properties وYAML؟
ج نعم، لكن في حالة تكرار الخصائص، فإن تعريف properties له الأسبقية. يُوصى باستخدام أحدهما فقط لتجنب الارتباك. نوصي بـ YAML لأنه يوفر هيكلاً هرمياً أوضح.
س كيف أُعطّل الشعار؟
ج اضبط spring.main.banner-mode=off في ملف التهيئة، أو app.setBannerMode(Banner.Mode.OFF) في الكود.
س ماذا أفعل عند ظهور خطأ "Port 8080 already in use" عند تشغيل التطبيق؟
ج عدّل server.port=8081، أو حدد العملية التي تستخدم المنفذ وأنهها: lsof -i :8080 (Linux/Mac) أو netstat -ano | findstr 8080 (Windows).
س ما الذي يسبب بطء التشغيل؟
ج الأسباب الشائعة: 1) مسار الأصناف كبير جداً مما يجعل المسح يستغرق وقتاً؛ 2) Hibernate ddl-auto=validate يسبب اتصالاً بطيئاً بقواعد بيانات بعيدة؛ 3) تهيئات تلقائية غير ضرورية لم يتم استبعادها. استخدم وضع --debug لعرض التفاصيل.
س كيف أحدد صنف الدخول الرئيسي؟
ج قم بتهيئته باستخدام <mainClass> في إضافة Maven؛ شغّل الصنف الذي يحتوي على طريقة main مباشرة في IDE؛ إضافة Spring Boot Maven ستكتشفه تلقائياً أثناء التعبئة.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): أنشئ مشروع Spring Boot، خصّص banner.txt، غيّر منفذ الخدمة إلى 9090، وبعد تشغيل المشروع، تحقق من إمكانية الوصول إلى نقطة النهاية /api/hello.

  2. تمرين متقدم (الصعوبة ⭐⭐): استبدل SpringApplicationBuilder بدلاً من SpringApplication.run()، عطّل الشعار، اضبط مستوى السجل إلى DEBUG، وخصص نقطة نهاية /api/app-info لإرجاع اسم التطبيق وإصدار Java.

  3. تحدٍ (الصعوبة: ⭐⭐⭐): نفّذ StartupListener وApplicationListener<ApplicationStartedEvent>، سجّل وقت بدء تشغيل التطبيق واطبعه في السجل. فكّر في الدافع التصميمي وراء آلية الأحداث في Spring Boot.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%