Skip to content

บทที่ 0 — Spring Framework คืออะไร และทำไมเรียน

(Spring = framework เขียน backend ของภาษา Java — ไม่ใช่ฤดูใบไม้ผลิ)

สารบัญ Spring Boot | บทที่ 1: First Spring Boot App →

ก่อนจะลงโค้ด เราจะตอบคำถาม 4 ข้อ ที่ถ้าไม่เข้าใจตั้งแต่ต้น Spring จะเหมือนเวทมนตร์:

  1. ปัญหาของ Java ที่เขียน backend แบบ "เปล่า ๆ" คืออะไร?
  2. IoC (Inversion of Control — กลับด้านการควบคุม) คืออะไร — แปลให้เห็นภาพ
  3. DI (Dependency Injection — การฉีดของที่ต้องใช้) คืออะไร — เกี่ยวกับ IoC ยังไง
  4. Spring vs Spring Boot — ต่างกันยังไง

หลังจบบทคุณจะ "เข้าใจวัตถุประสงค์" ของ Spring — บทต่อ ๆ ไปจะเข้าใจง่ายขึ้นมาก

📋 ก่อนเริ่ม — ต้องผ่านอะไรมาก่อน?

  • ✅ Java พื้นฐาน (Java บทที่ 1–8: class, object, interface, generics, exception)
  • 🔑 ศัพท์ที่จะเจอบ่อยในบทนี้ (ไม่ต้องท่อง เดี๋ยวอธิบายระหว่างทาง):
    • dependency (ดีเพน-เดน-ซี) = "สิ่งที่ของชิ้นหนึ่งต้องใช้" เช่น UserService ต้องใช้ UserRepositoryUserRepository คือ dependency ของ UserService
    • container (คอนเทนเนอร์) = "กล่องเก็บของ" ที่ Spring ใช้เก็บ object ทั้งหมดไว้ + สร้าง/ส่งให้กัน
    • inject (อิน-เจกต์) = "ฉีด/ยัดเข้าไป" — เอา object หนึ่งส่งเข้าไปให้อีก object ใช้
    • annotation (แอนโน-เท-ชัน) = ป้ายกำกับที่เขียนนำหน้าด้วย @ เช่น @Component เป็นการ "บอกใบ้" ให้ Spring รู้ว่าต้องทำอะไรกับ class นี้

1. ปัญหา: เขียน backend Java แบบ "เปล่า ๆ" คือยังไง

สมมติเราจะเขียนระบบเล็ก ๆ — มี API ให้ดึงข้อมูล user:

java
class UserService {
    UserRepository repo;
    EmailService email;
    AuditLogger logger;
    
    User getUser(String id) {
        logger.log("get user " + id);
        return repo.findById(id);
    }
    
    void sendWelcome(User u) {
        email.send(u.getEmail(), "Welcome");
        logger.log("sent welcome to " + u.getEmail());
    }
}

UserService ต้องใช้ UserRepository, EmailService, AuditLogger — เรียก dependencies

ทำไงให้ UserService มี dependency เหล่านี้?

วิธีที่ 1: สร้างเอง

java
class UserService {
    UserRepository repo = new UserRepository();
    EmailService email = new EmailService();
    AuditLogger logger = new AuditLogger();
}

ปัญหา:

  • Coupling (คับ-พลิ่ง — การผูกติด/พึ่งพากันแน่น) — UserService รู้ว่า UserRepository ต้อง new ยังไง (แต่ในงานจริง UserRepository ต้องการ database connection ที่ต้องการ config — UserService ไม่ควรรู้)
  • Test ยาก — อยากเปลี่ยน UserRepository เป็น mock ใน test ทำไม่ได้
  • ขยายยาก (Hard to extend) — เปลี่ยน EmailService → MockEmailService สำหรับ dev ทำไม่ได้

วิธีที่ 2: ส่งผ่าน constructor (better)

java
class UserService {
    UserRepository repo;
    EmailService email;
    AuditLogger logger;
    
    UserService(UserRepository repo, EmailService email, AuditLogger logger) {
        this.repo = repo;
        this.email = email;
        this.logger = logger;
    }
}

ใช้:

java
// pseudo-code — ดูไอเดียพอ ไม่ต้องพิมพ์ตาม
// ต้องสร้าง dependency (สิ่งที่ต้องใช้) ก่อน
DataSource ds = createDataSource(...);  // DataSource = ตัวเชื่อมต่อ database
UserRepository repo = new UserRepository(ds);
EmailConfig emailCfg = loadEmailConfig(...);
EmailService email = new EmailService(emailCfg);
AuditConfig auditCfg = loadAuditConfig(...);
AuditLogger logger = new AuditLogger(auditCfg);

// ค่อยสร้าง service (ตัวที่มี business logic)
UserService service = new UserService(repo, email, logger);

ปัญหาใหม่:

  • โค้ดที่ "wire dependency" (ต่อสายให้ object รู้ว่าใครต้องใช้ใคร) ยาว + ซับซ้อน
  • ถ้ามี 100 service → wiring code ยาว 1000+ บรรทัด
  • ลำดับสร้างผิดง่าย
  • เปลี่ยน implementation 1 ตัว → แก้หลายที่

นี่คือปัญหาที่ Spring แก้

Spring เป็น container ที่:

  • เก็บ object (dependency) ทั้งหมดไว้
  • รู้ว่า object แต่ละตัวต้องการอะไร
  • สร้างให้ + inject ให้ อัตโนมัติ
  • เราแค่บอก "เนี่ย UserService ต้องการ UserRepository" — Spring ทำที่เหลือ

2. IoC — Inversion of Control

IoC = "Inversion of Control" — กลับด้านการควบคุม

แบบเดิม (ไม่มี IoC)

โค้ดของเรา ควบคุม การสร้าง dependency:

java
class UserService {
    UserRepository repo = new UserRepository();   // ฉัน (โค้ดเรา) สร้างเอง
}

ใครเลือก implementation? — UserService

แบบ IoC

โค้ดของเรา ขอ dependency จาก framework:

java
class UserService {
    UserRepository repo;
    
    UserService(UserRepository repo) {
        this.repo = repo;     // ใครก็ได้ส่งมาให้ (เราไม่ได้สร้างเอง)
    }
}

ใครเลือก implementation? — Framework (Spring) — "ฉัน framework เลือกให้คุณ"

คำว่า "inverted": ปกติ class A เรียก B → ตอนนี้ B ถูกส่งให้ A — กลับด้าน

Analogy: ร้านอาหาร vs ทำกินเอง

  • ไม่มี IoC = ทำกินเอง → ต้องไปซื้อของ ปอกหั่น ปรุง ล้างจาน → คุมทุกขั้น แต่เหนื่อย
  • มี IoC = ไปร้าน → บอกว่า "ขอข้าวผัด" → ครัวจัดการให้ → คุณกินอย่างเดียว
    • คุณบอก "ขอ" (declare dependency) ไม่ใช่ "ทำเอง" (instantiate)
    • ร้าน (Spring) ตัดสินใจว่าใช้กระทะอันไหน เชฟคนไหน

อีก analogy คลาสสิกคือ "Don't call us, we'll call you" (อย่าโทรหาเรา เดี๋ยวเราโทรหาคุณ) — เรียกว่า Hollywood Principle หมายความว่า framework เป็นฝ่ายเรียกโค้ดเรา ไม่ใช่เราเรียกมัน เปรียบได้กับตอนสัมภาษณ์งาน — HR เป็นฝ่ายโทรหาคุณเอง ไม่ใช่คุณต้องโทรไปถามผลสัมภาษณ์ คุณแค่รอ (declare) ว่าพร้อม

Framework vs Library — ความต่างที่สำคัญ

ใหม่ๆ คนสับสน 2 คำนี้:

LibraryFramework
ใครเรียกใครคุณเรียก libraryFramework เรียกคุณ (callbacks — โค้ดของคุณที่ Spring เรียกให้ เช่น method hello() ที่คุณเขียนแต่ Spring เป็นคนเรียกตอนมี HTTP request เข้ามา)
ใครคุม flowคุณFramework
ตัวอย่างApache Commons, Jackson, GuavaSpring, Angular, Spring Boot

Spring = framework เพราะมัน เรียก method ของคุณ ตอนที่มันเลือก — ไม่ใช่คุณเรียก Spring โดยตรง

ภาพ:


3. DI — Dependency Injection

DI = "Dependency Injection" — วิธีหนึ่งของ IoC

IoC เป็นแนวคิดกว้าง ๆ ว่า "ใครคุมการสร้าง object" — มีหลายวิธีทำ DI เป็นวิธีที่นิยมที่สุด (วิธีอื่นเช่น Service Locator มี แต่ Spring ใช้ DI เป็นหลัก)

DI = "ฉีด dependency เข้าไปใน object แทนที่จะให้มันหาเอง"

3 รูปแบบ DI ที่ Spring รองรับ

📖 @Autowired คืออะไร (กางก่อนเข้าโค้ดข้างล่าง): ป้ายบอก Spring ว่า "ฉีด object ที่ตรงกับ type (ประเภทข้อมูล เช่น UserRepository, EmailService) นี้เข้ามาให้หน่อย" — Spring จะหาว่า object ไหนใน container (เดี๋ยว §4 จะเรียกสิ่งนี้ว่า bean) มี type ตรงกัน แล้วเอามาใส่ให้ (ไม่ต้อง new เอง) วางได้บน constructor, setter, หรือ field — แต่บน constructor ดีที่สุด

3.1 Constructor injection (แนะนำ)

💡 Spring 4.3+: ถ้ามี constructor เดียว ไม่ต้องเขียน @Autowired ก็ได้ (Spring ฉีดให้อัตโนมัติ) — หมายเหตุ: เป็น Spring version ไม่ใช่ Java version

java
class UserService {
    final UserRepository repo;

    @Autowired
    UserService(UserRepository repo) {
        this.repo = repo;
    }
}

ข้อดี:

  • field เป็น final ได้ — immutable
  • บังคับ dependency ทั้งหมดตอน new
  • test ง่าย — แค่ส่ง mock ผ่าน constructor

3.2 Setter injection

java
class UserService {
    UserRepository repo;
    
    @Autowired
    void setRepo(UserRepository repo) {
        this.repo = repo;
    }
}

ใช้น้อย — ไม่บังคับ dependency, field ไม่ final

3.3 Field injection (ไม่แนะนำ)

java
class UserService {
    @Autowired
    UserRepository repo;
}

ดูเหมือนสั้น — แต่:

  • 🚫 NEVER use in new code — Spring team ไม่แนะนำ และ IDE อย่าง IntelliJ จะขีดเส้นเตือน "Field injection is not recommended" (Spring เองไม่ throw error แต่ชุมชนหลีกเลี่ยงและจะผ่าน code review ได้ยาก)
  • ❌ test ยาก (ต้อง reflection)
  • ❌ field ไม่ final ได้ (mutability problem)
  • ❌ ไม่เห็น dependency ใน constructor (hidden)

กฎทอง: ใช้ constructor injection เสมอ


4. Bean — object ที่ Spring จัดการ

ใน Spring, object ที่ container เก็บไว้เรียกว่า bean

📖 อะไรคือ @SpringBootApplication? — ป้ายที่วางบน main class ของแอป มันเปิด Spring container + auto-config ให้ครบในตัวเดียว (รายละเอียดเต็มในบทที่ 1)

📖 lifecycle (ไลฟ์-ไซ-เคิล) = วงจรชีวิตของ bean: สร้าง → inject → ใช้งาน → ทำลายตอน app ปิด — Spring คุมทั้งหมดให้

java
@Component        // บอก Spring ว่า "นี่คือ bean จัดการให้ที"
class UserService {
    final UserRepository repo;
    
    UserService(UserRepository repo) {
        this.repo = repo;
    }
}

@Component
class UserRepository { ... }

Spring จะ:

  1. Scan หา class ที่มี @Component
  2. สร้าง instance (เรียก constructor)
  3. เก็บใน "container"
  4. ตอนสร้าง UserService — เห็นว่ารับ UserRepository ใน constructor → หา bean ของ UserRepository → ส่งให้

💡 ใคร scan?@SpringBootApplication บน main class จะ scan ตั้งแต่ package ของ main class ลงไปทั้งหมด อัตโนมัติ — วาง class ใน sub-package ก็เจอ แต่ถ้าวางนอก package tree นั้นจะไม่เจอ

Annotation แบบเฉพาะของ @Component

  • @Component — ทั่วไป
  • @Service — สำหรับ business logic
  • @Repository — สำหรับ data access (โค้ดติดต่อ database) มีของเสริมชื่อ exception translation (การแปลง error จาก DB ให้เป็นรูปแบบมาตรฐานของ Spring):
    • เวลา database ขัดข้อง @Repository จะแปลง error ให้เป็น DataAccessException มาตรฐาน ไม่ว่าจะใช้ MySQL หรือ PostgreSQL
    • ผลคือเปลี่ยน DB ก็ไม่ต้องแก้ catch — รายละเอียดเต็มในบทที่ 2
  • @Controller — สำหรับ web controller (return ชื่อ template เพื่อให้ server ประกอบเป็นหน้า HTML ส่งกลับ — หนังสือเล่มนี้เน้น REST API จึงแทบไม่ได้ใช้ @Controller แบบนี้)
  • @RestController@Controller + @ResponseBody (= บอกว่า return value ให้แปลงเป็น JSON ส่งกลับ ไม่ต้อง render หน้า HTML) เหมาะกับ REST API ที่คืน JSON ตรง ๆ

ทุกตัวคือ @Component เหมือนกัน — แค่ระบุ "บทบาท" ให้ชัด


5. Spring vs Spring Boot

Spring Framework (เก่า — ยังใช้)

  • container + DI
  • abstraction สำหรับ web, data, security, ฯลฯ
  • ปัญหา: configure ยุ่งยาก — XML config ยาว, ต้อง set up Tomcat, DispatcherServlet ฯลฯ

ตัวอย่าง Spring แบบเก่า (XML):

xml
<beans>
    <bean id="userRepo" class="com.example.UserRepository">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="userService" class="com.example.UserService">
        <constructor-arg ref="userRepo"/>
    </bean>
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="url" value="jdbc:postgresql://localhost/db"/>
        <property name="username" value="admin"/>  <!-- ⚠️ ในงานจริงห้าม hardcode credential ตรงนี้ — ใช้ environment variable หรือ secrets vault แทน -->
    </bean>
</beans>

ปวดหัว 😩

Spring Boot (2014+, ใช้ปัจจุบัน)

  • ครอบ Spring + opinionated (โอ-พิ-เนีย-เนเทด — "มีความเห็นของตัวเอง" คือ framework เลือก default ที่ดีไว้ให้แล้ว เราไม่ต้องตั้งค่าเองทุกอย่าง)
  • ไม่มี XML — ใช้ annotation + properties file
  • Embedded server (เซิร์ฟเวอร์ฝังในตัว) — รวม Tomcat (โปรแกรม web server ที่รับ HTTP) มาในไฟล์ jar เดียวกัน (java -jar app.jar ก็ run server แล้ว)
  • Starter dependency (แพ็คคู่ของ library — แปะตัวเดียวได้ทุกอย่างที่ต้องคู่กัน) — spring-boot-starter-web แปะตัวเดียวได้ทั้ง web + JSON + validation
  • Auto-configuration — Spring เดาให้ว่าต้องการอะไรจาก classpath (รายการ jar/ไฟล์ .class ที่ Java โหลดมาเปิดใช้งานตอนรัน — เหมือน PATH ของ OS แต่ใช้กับ Java)

ตัวอย่าง Spring Boot:

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

@RestController
class HelloController {
    @GetMapping("/")
    String hello() { return "Hello, Spring!"; }
}

2 class — server พร้อม run

Convention เทียบสั้น ๆ

Spring (เก่า)Spring Boot
ConfigXML / Java configannotation + application.properties
Serverconfigure Tomcat แยกembedded — run จาก main
Dependencyเลือก library ทีละตัวstarter — group เลย
Setupใช้เวลาstart.spring.io 30 วินาที (เว็บ generate project สำเร็จรูป — จะใช้จริงในบทที่ 1)

ปี 2026 — ใช้ Spring Boot เป็นค่าเริ่มต้น


6. Spring Boot ทำอะไรให้ฟรี

ตอน start app:

  1. Scan annotation (@Component, @Service ฯลฯ) → สร้าง bean
  2. Inject dependency อัตโนมัติ
  3. Detect dependency บน classpath → auto-configure
    • เห็น spring-boot-starter-data-jpa → configure DataSource (ตัวจัดการ connection ไป DB) + EntityManager (ตัวจัดการ object ↔ DB mapping) — รายละเอียดบทที่ 2
    • เห็น spring-boot-starter-web → start embedded Tomcat
  4. Map URL → controller method
  5. Convert JSON ↔ object อัตโนมัติ (ผ่าน library ชื่อ Jackson ที่ Spring Boot แถมมาให้)
  6. Manage transaction (@Transactional — รายละเอียดในบทที่ 2)
  7. Caching (บทที่ 11), scheduling (บทที่ 13), async — ถ้าเปิด

ทั้งหมดนี้ developer แค่บอก "ฉันต้องการอะไร" — Spring จัดการ "ยังไง"


7. ภาพรวม project structure

text
my-app/
├── pom.xml                   ← Maven config
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/
│   │   │       ├── Application.java              ← main()
│   │   │       ├── controller/
│   │   │       │   └── UserController.java       ← @RestController
│   │   │       ├── service/
│   │   │       │   └── UserService.java          ← @Service
│   │   │       ├── repository/
│   │   │       │   └── UserRepository.java       ← @Repository
│   │   │       └── model/
│   │   │           └── User.java                 ← entity / record
│   │   └── resources/
│   │       ├── application.properties            ← config
│   │       └── static/                           ← static files (CSS, JS)
│   └── test/
│       └── java/                                 ← tests
└── target/                   ← compile output (auto)

Layer

ControllerServiceRepositoryDatabase

  • Controller — รับ HTTP request, แปลง JSON
  • Service — business logic
  • Repository — เข้าถึง database
  • ไม่ข้าม layer (controller อย่าเรียก repository ตรง)

8. ทำไม Spring Boot คือ "the framework" ของ Java backend

  • Mature — 10 ปี + ใช้ใน Netflix, ธนาคาร, government
  • Ecosystem — Spring Data, Spring Security, Spring Cloud (microservices), Spring Batch ฯลฯ
  • Documentation — เยอะ + ดี
  • Community — Stack Overflow ตอบครบ
  • Job market — Java backend = Spring Boot 90%

ปี 2026:

  • Spring Boot 3.x = Java 17 ขั้นต่ำ บน Spring Framework 6.x; 3.2+ เพิ่มการรองรับ Virtual Threads (เหมาะสุดกับ Java 21); 3.4+ แนะนำสำหรับ project ใหม่ — หนังสือเล่มนี้ใช้ Java 21 ตลอด ติดตั้ง Java 21 ก่อนเริ่มบทที่ 1
  • รองรับ feature ใหม่ ๆ ของ JVM (เช่น Virtual Threads, GraalVM Native Image, Reactive/WebFlux) — รายละเอียดบทที่ 10 และ 15 ตอนนี้ยังไม่ต้องสนใจ
  • (last reviewed: 2026-06 — ตรวจ release notes ทางการก่อนใช้)
🟡 สำหรับคนที่เคย deploy Spring Boot 2 มาก่อน — Jakarta EE migration (ข้ามได้ถ้าเพิ่งเริ่ม)
  • Spring Boot 3.x ย้าย namespace (กลุ่ม package ของ Java) จาก javax.*jakarta.* ทุก import (Servlet, Persistence, Validation, Annotation, Transaction ฯลฯ)
  • ทุก library ที่ใช้ใน app ต้องรองรับ Jakarta — Hibernate ≥6, Tomcat ≥10, Jersey ≥3
  • migration tool: eclipse-transformer ช่วย rewrite ทั้ง project, แต่ต้อง verify ทุก dependency
  • ถ้าอ่าน Stack Overflow หรือ blog เก่าที่ใช้ javax.persistence.* ต้องแปลเป็น jakarta.persistence.* ทุกครั้ง
  • ถ้าเริ่ม project ใหม่ในปี 2026 — ข้ามได้ ส่วนนี้สำหรับคนย้าย project เก่าเท่านั้น
📚 8.1 ApplicationContext vs BeanFactory + 8.2 Bean scope (อ่านได้ตอนคล่องแล้ว — บทที่ 0 ผ่านได้โดยไม่ต้องเข้าใจส่วนนี้)

8.1 ApplicationContext vs BeanFactory

"Spring container" ที่บทนี้พูดถึงจริง ๆ มี 2 ระดับ:

Interfaceคืออะไรใช้เมื่อไหร่
BeanFactorycontainer ระดับล่างสุด — รู้จัก bean lazy + DI พื้นฐานเท่านั้นrarely used directly (รากของทุก context)
ApplicationContextextends BeanFactory — เพิ่ม eager init, AOP (การเพิ่มโค้ดข้ามหลาย class แบบอัตโนมัติ), event publishing (การแพร่เหตุการณ์ภายใน app), i18n (internationalization = รองรับหลายภาษา), environment abstraction (ชั้นซ่อนความแตกต่างของ config แต่ละ environment), resource loading (การโหลดไฟล์/resource)ใช้ตัวนี้ตลอด — Spring Boot สร้างให้อัตโนมัติ

Spring Boot สร้าง ApplicationContext ให้ตอน SpringApplication.run(...) — bean ทั้งหมดเข้าไปอยู่ใน context นี้

java
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
        // ctx.getBean(UserService.class) — เข้าถึง bean ผ่าน context ได้ (rare)
    }
}

8.2 Bean scope + thread-safety

bean default คือ singleton (1 instance ต่อ container) — ดี สำหรับ stateless service แต่ อันตราย ถ้าเก็บ mutable state ใน field เพราะหลาย thread เข้าพร้อมกัน:

Scopeทำงาน
singleton (default)1 instance — ห้ามเก็บ mutable state (ข้อมูลที่เปลี่ยนได้) ใน field
prototypeสร้างใหม่ทุกครั้งที่ inject
request (web)1 instance ต่อ HTTP request
session (web)1 instance ต่อ HTTP session
java
@Service
@Scope("singleton")    // implicit default
public class UserService {
    private final UserRepository repo;   // ✅ final + immutable — thread-safe
    private List<User> cache = new ArrayList<>();  // ❌ mutable field ใน singleton = race condition
    // constructor + methods ถูกตัดออกเพื่อความกระชับ — ตัวอย่างนี้เน้นแสดงเฉพาะประเด็น thread-safety
}

ศัพท์ multithreading ที่ใช้ในกล่องนี้ (ดู Java บทที่ 9):

  • mutable state = ข้อมูลที่เปลี่ยนได้
  • race condition = สถานการณ์ที่ 2 thread แก้ของพร้อมกันแล้วผลปนกัน
  • stateless = ไม่เก็บข้อมูลใน field
  • thread-safe = ปลอดภัยเมื่อหลาย thread ใช้พร้อมกัน

9. Checkpoint ความเข้าใจ

🛠️ Checkpoint 0.1 — ทบทวน

ลองตอบในใจ:

  1. IoC คืออะไร ในประโยคเดียว
  2. DI ต่างจาก IoC ยังไง
  3. ทำไม constructor injection ดีกว่า field injection
  4. Bean คืออะไร
  5. Spring vs Spring Boot ต่างกันอย่างไร
📖 เฉลย
  1. กลับด้านการควบคุม — แทนที่ class จะสร้าง dependency เอง, framework สร้างและฉีดให้
  2. DI เป็น "วิธีหนึ่ง" ของ IoC — ใช้การฉีด dependency ผ่าน constructor/setter/field
  3. constructor: field final ได้, test ง่าย (mock ส่งผ่าน constructor), บังคับ dependency ตอน new
  4. object ที่ Spring container จัดการ — สร้างให้, inject ให้, จัดการ lifecycle
  5. Spring = framework core (DI + AOP + ฯลฯ); Spring Boot ครอบ Spring + opinionated config + embedded server

🛠️ Checkpoint 0.2 — ออกแบบ

มีโจทย์: สร้างระบบจัดการคำสั่งซื้อ มี components:

  • OrderController — รับ HTTP
  • OrderService — business logic
  • OrderRepository — เข้าถึง DB
  • PaymentClient — เรียก external API
  • NotificationService — ส่ง email

ถ้าใช้ Spring จะมี dependency อะไรเข้าใครยังไง?

📖 เฉลย
  • OrderController ขอ OrderService ผ่าน constructor
  • OrderService ขอ OrderRepository, PaymentClient, NotificationService ผ่าน constructor

Spring เห็น @Component ทุกตัว → สร้างให้ → inject ให้ — ไม่ต้องเขียน new เอง


10. สรุปบท

✅ ปัญหา: เขียน Java เปล่า ๆ → coupling สูง, test ยาก, wiring code ยาว ✅ IoC = framework ควบคุมการสร้าง object แทนเรา ✅ DI = วิธีของ IoC — ฉีด dependency ผ่าน constructor (แนะนำ) / setter / field ✅ Bean = object ที่ Spring container เก็บไว้ ✅ @Component / @Service / @Repository / @Controller / @RestController = annotation บอก Spring ✅ Spring Boot ครอบ Spring + auto-configuration + embedded server + starter dependency ✅ Layer: Controller → Service → Repository — ไม่ข้าม

→ ไปบทที่ 1: First Spring Boot App


🔤 Glossary · 📋 Style guide · 📅 last_verified: 2026-06-23