Spring Production-Ready/Tổng kết — Modern Java trong Spring
9/26
Bài 9 / 26~6 phútModern Java trong SpringMiễn phí lượt xem

Tổng kết — Modern Java trong Spring

Cheat sheet record DTO, quyết định bật virtual threads, RestClient so với @HttpExchange, sealed Result, kèm self-assessment năm năng lực của module.

TL;DR: Module 01 bóc bốn chỗ Java hiện đại chạm vào runtime Spring Boot: record khoá cửa mutation ở tầng DTO, virtual threads đổi cách Boot cấp thread cho tải I/O-bound (kèm ba cạm bẫy khi bật), RestClient/@HttpExchange gọi HTTP ra ngoài có timeout và xử lý lỗi tường minh, và sealed Result thay exception cho lỗi nghiệp vụ dự đoán được. Đây là 1 trang để bookmark: cheat sheet quyết định nhanh, liên hệ hai module sau, và self-assessment năm năng lực.

Đã đi qua những gì

Bài 01 khoá cửa mutation bằng record: Jackson bind JSON qua canonical constructor thay vì setter, nên không còn chỗ nào ghi đè giữa đường, nhưng JPA entity vẫn cần class mutable vì Hibernate cần constructor rỗng, field ghi được và class không final để proxy lazy-loading. Bài 02 bật spring.threads.virtual.enabled=true, đúng ba chỗ đổi cùng lúc: Tomcat, @Async, taskScheduler, và lằn ranh thắng-thua chỉ có một câu hỏi: phần lớn thời gian request là chờ hay là tính. Bài 03 cho thấy bật cấu hình đó chưa đủ: pinning khi block trong synchronized, ThreadLocal nhân bản theo số thread tăng vọt, và pool cũ từng âm thầm làm van chặn tải giờ không còn. Bài 04 dựng RestClient với timeout tường minh, chặn đúng lớp lỗi gây treo cả node ở bài trước. Bài 05 gói chuỗi endpoint lặp lại thành interface @HttpExchange, proxy vẫn giao việc gửi/nhận cho đúng RestClient đã cấu hình. Bài 06 khép mảng kỹ thuật bằng sealed Result: lỗi nghiệp vụ dự đoán được là kết quả kiểu dữ liệu, không phải exception, và switch exhaustive bắt lỗi ngay lúc build. Mini-challenge (bài 07) ráp cả bốn kỹ thuật vào TaskFlow rồi đo lại throughput.

flowchart LR
  A["Record DTO"] --> B["Virtual threads"]
  B --> C["Cam bay VT"]
  C --> D["RestClient"]
  D --> E["HttpExchange"]
  E --> F["Sealed Result"]

🗺️ Cheat sheet

Chủ đềQuyết định / cơ chế chínhPitfall lớn nhất
Record ở ranh giới HTTPDTO request/response và JPA projection: dùng được. JPA entity và bean cần setter: không, vì thiếu constructor rỗng, field không mutable, class final chặn proxyKhai canonical constructor tường minh đủ tham số làm mất tự động copy constraint Bean Validation, không cảnh báo gì
Bật virtual threadsBật khi phần lớn thời gian request là chờ I/O (gọi API, query DB); đừng bật khi việc nặng là tính CPU hoặc đã dùng WebFlux non-blocking thật sựĐo latency một request rồi kết luận "không tác dụng" — phải đo throughput ở tải vượt xa pool cũ mới thấy khác biệt
Ba cạm bẫy virtual threadsPinning (block trong synchronized, JDK 21 luôn ghim, JDK 24 JEP 491 gỡ phần lớn) · ThreadLocal nhân bản theo số thread (vài trăm lên hàng nghìn) · mất backpressure (pool cũ từng là van chặn tải)Tưởng bật một cờ config là xong, không kiểm pinning bằng JFR (jdk.VirtualThreadPinned) và không dựng lại Semaphore/rate limiter thay pool cũ
RestClient so với @HttpExchangeFluent (RestClient) khi cần rẽ nhánh theo status code, header động phức tạp, hoặc streaming; declarative (@HttpExchange) khi hợp đồng ổn định và lặp lại nhiều endpointQuên khai timeout (chờ downstream vô thời hạn) hoặc onStatus chỉ bắt 4xx mà quên 5xx
Sealed Result so với exceptionResult cho lỗi nghiệp vụ dự đoán được, nằm trong đặc tả (hết hàng, quá hạn mức); exception cho sự cố ngoài dự kiến hoặc lỗi phải lan qua nhiều tầng gọi nhau@Transactional không tự rollback khi trả về nhánh lỗi của Result vì đó là return bình thường — phải validate trước khi ghi, hoặc chủ động setRollbackOnly()

Liên hệ các module khác

  • Module 02 — Observability & Production-ready: virtual thread không map 1-1 với OS thread nữa, nên module 02 dạy Observation API và tracing OTLP nối trace ID vào log — đúng công cụ để đọc lại đúng luồng xử lý khi thread dump không còn nói lên nhiều điều. RestClient/@HttpExchange ở module này cũng là chỗ Observation API tự động instrument khi bạn gọi ra ngoài.
  • Module 03 — Caching, Async & Scheduling: @Async ở module 03 chạy trên virtual thread đúng theo cấu hình đã bật ở bài 02; pitfall ThreadLocal phình to ở bài 03 áp thẳng vào bất kỳ KeyGenerator cache nào tự đọc context theo thread. Sealed Result tiếp tục làm kiểu trả về khi luồng phụ qua Spring Events cần báo kết quả thành công hay thất bại.

✅ Self-assessment

Bạn đã đạt module này nếu trả lời được:

  • Dựng được record làm DTO request/response, và giải thích được vì sao nó gãy khi dùng làm JPA entity hay bean cần setter injection — nếu chưa chắc, đọc lại bài 01 mục "Ranh giới record: chỗ hợp, chỗ gãy".
  • Quyết định đúng có nên bật virtual threads hay không, dựa trên hồ sơ tải I/O-bound hay CPU-bound của service — nếu chưa chắc, đọc lại bài 02 mục "Bật hay không — bảng quyết định".
  • Chẩn đoán được ba hỏng hóc hay gặp sau khi bật virtual threads: pinning, ThreadLocal phình to, và mất backpressure của pool — nếu chưa chắc, đọc lại bài 03.
  • Dựng được client gọi HTTP ra ngoài bằng RestClient hoặc @HttpExchange, với timeout và xử lý lỗi tường minh — nếu chưa chắc, đọc lại bài 04 mục "Timeout: mặc định là chờ mãi" và bài 05 mục "Cơ chế bên dưới: proxy quanh RestClient".
  • Model được kết quả nghiệp vụ bằng sealed type và pattern matching, rồi map sang ProblemDetail thay vì ném exception — nếu chưa chắc, đọc lại bài 06 mục "Dựng Result bằng sealed interface" và phần Pitfall về @Transactional.

🚀 What's next

Bạn vừa hiện đại hoá tầng Java bên trong TaskFlow: dữ liệu bất biến, runtime request phù hợp tải, client ra ngoài có kiểm soát, kết quả nghiệp vụ tường minh. Câu hỏi tiếp theo tự nhiên là: hệ thống này có đang chạy khoẻ không, và bạn biết được điều đó bằng cách nào? Module 02 "Observability & Production-ready" dạy Actuator, Micrometer, percentile và tracing OTLP để trả lời đúng câu hỏi đó.

Observability & Production-ready — tổng quan

📚 Tài liệu mở rộng

📚 Spec & tài liệu chính thức
📚 Blog kỹ thuật

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên

Bài tiếp theo

Observability & Production-ready — tổng quan