Spring Production-Ready/Module 03 — Caching, Async & Scheduling: tổng quan
19/26
Bài 19 / 26~8 phútCaching, Async & SchedulingMiễn phí lượt xem

Module 03 — Caching, Async & Scheduling: tổng quan

Cache, chạy nền, lịch định kỳ và event đều đi qua cùng một AOP proxy, nên chia sẻ đúng một họ cạm bẫy: self-call, ranh giới thread, ranh giới transaction.

TL;DR: Module này dạy bốn cơ chế Spring dùng để đẩy việc ra khỏi luồng request chính: cache (@Cacheable), chạy nền (@Async), lịch định kỳ (@Scheduled), và Spring Events. Cả bốn, cùng @Transactional bạn đã học ở khoá trước, đi qua đúng một cơ chế nền: AOP proxy. Vì chia sẻ chung cơ chế, chúng chia sẻ chung một họ cạm bẫy — self-call bỏ qua proxy, ranh giới thread không tự mang theo ThreadLocal, ranh giới transaction không đợi việc phụ chạy xong. Module đi theo đúng thứ tự học một cơ chế rồi áp nó vào bốn bài toán khác nhau, chốt lại bằng một mini-challenge ráp cả năm mảnh vào một tính năng thật.

Vì sao module này tồn tại

TaskFlow đã có RestClient gọi API ngoài, có Actuator theo dõi sức khoẻ, có Micrometer đo latency. Nhưng ba vấn đề vẫn lặp lại mỗi tuần: endpoint báo cáo chậm vì tính lại từ đầu mỗi lần gọi dù dữ liệu bên dưới chỉ đổi vài lần một ngày, request tạo project bị chặn hai giây chờ SMTP trả lời trong khi người dùng chẳng cần biết email đã gửi xong chưa, và job gửi báo cáo đêm chạy trùng ba lần vì ứng dụng giờ chạy nhiều instance sau load balancer.

Bốn annotation của module này giải quyết đúng ba vấn đề đó, nhưng điểm đáng học không nằm ở cú pháp từng annotation. Nó nằm ở chỗ @Cacheable, @Async, @Scheduled và cơ chế publish/subscribe của Spring Events đều dựa trên đúng một nền tảng đã học ở bài AOP Proxy của spring-core: container bọc bean bằng một proxy, và proxy chỉ chèn được logic tại lời gọi đi qua nó. Hiểu đúng cơ chế đó một lần, bạn nhận ra ngay vì sao annotation lặng lẽ mất tác dụng khi gọi qua this, vì sao dữ liệu gắn với thread (MDC, SecurityContextHolder) biến mất khi việc chuyển sang thread khác, và vì sao transaction không đợi một việc phụ chạy xong trước khi commit.

flowchart TB
    P["AOP Proxy - hoc o spring-core"] --> C["Bai 01: Cacheable"]
    P --> A["Bai 03: Async"]
    P --> S["Bai 04: Scheduled"]
    P --> T["Transactional - hoc o spring-rest-data"]
    C --> B02["Bai 02: chon Caffeine hay Redis"]
    A --> B05["Bai 05: Spring Events"]
    S --> B05
    T --> B05
    B02 --> M["Bai 06: Mini-challenge TaskFlow v6"]
    B05 --> M

Sau module này bạn sẽ

  • Implement @Cacheable@CacheEvict với key strategy đúng, tránh bẫy self-call của proxy.
  • Compare Caffeine local với Redis distributed theo trục invalidation, serialization và chi phí vận hành.
  • Implement @Async đúng executor và diagnose exception bị nuốt khi method trả về void.
  • Choose fixed rate, fixed delay hay cron, và design chống chạy trùng khi chạy nhiều instance.
  • Design luồng phụ bằng Spring Events và justify khi nào cần @TransactionalEventListener AFTER_COMMIT.

Lộ trình module

Thứ tự năm bài không ngẫu nhiên: mỗi bài dùng lại đúng cơ chế bài trước vừa dựng, chỉ đổi bài toán áp dụng.

  1. Cache abstraction: @Cacheable chạy qua proxy như thế nào, và vì sao self-call làm nó lặng lẽ không hoạt động?
  2. Caffeine hay Redis: cùng một annotation cho hai kết quả khác nhau tuỳ nơi đặt cache, vậy chọn theo trục nào khi TaskFlow chạy nhiều instance?
  3. Async và executor: trả void hay CompletableFuture quyết định exception đi đâu, và executor mặc định có đủ dùng cho mọi loại việc không?
  4. Scheduled: fixedRate, fixedDelay hay cron đếm mốc từ đâu, và job đêm chạy trùng ba lần khi có ba instance thì chặn bằng gì?
  5. Spring Events: @EventListener có thật sự chạy bất đồng bộ như cái tên gợi ý không, và khi nào bắt buộc cần @TransactionalEventListener AFTER_COMMIT?
  6. Mini-challenge: TaskFlow v6: ráp cả năm mảnh vào một tính năng thật, báo cáo đêm có cache, chạy nền và phát qua event.

Yêu cầu trước khi bắt đầu

Module này giả định bạn đã nắm cơ chế proxy đứng sau annotation, không dạy lại từ đầu:

Time budget

  • Module: khoảng 1 giờ 33 phút tổng (1 giờ 3 phút đọc 5 bài concept, 30 phút mini-challenge).
BàiChủ đềPhút
00Tổng quan8
01Cache abstraction13
02Caffeine hay Redis12
03Async và executor13
04Scheduled12
05Spring Events13
06Mini-challenge TaskFlow v630
07Tổng kết & cheat sheet6

Cách học module này hiệu quả

  • Đừng học năm bài như năm annotation rời rạc. Mỗi lần gặp một pitfall mới (self-call, exception bị nuốt, chạy trùng nhiều instance), tự hỏi ngược lại: nó có họ hàng nào ở bài trước không?
  • Bài 02 và bài 04 cùng dựng trên một tình huống: TaskFlow chạy ba instance sau load balancer. Nhớ lại đúng bối cảnh đó khi đọc bài 04 sẽ nhanh hơn đọc lại từ đầu.
  • Đừng bỏ qua mini-challenge (bài 06). Đó là chỗ duy nhất năm mảnh kiến thức ráp lại thành một tính năng chạy được, và là bằng chứng cho cả năm learning outcome ở trên.

Bài tiếp theo: Cache abstraction

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

Spring Cache — một annotation, một proxy, ba cái bẫy