Spring REST API & Data JPA
2/46
Bài 2 / 46~12 phútSpring MVC CoreLộ trình · chặng 15/21Miễn phí… lượt xem

DispatcherServlet: Kiến Trúc Front Controller Spring MVC

Khám phá kiến trúc DispatcherServlet trong Spring MVC, 9 bean hạ tầng cốt lõi, vòng đời xử lý request doDispatch và cơ chế auto-config.

TL;DR: DispatcherServlet là Front Controller duy nhất trong Spring MVC tiếp nhận toàn bộ HTTP request trước khi điều phối đến handler phù hợp. Kiến trúc này tập trung các logic dùng chung (xác thực, logging, chuyển đổi định dạng và bắt lỗi) về một điểm duy nhất thay vì lặp lại trên từng servlet riêng lẻ. Servlet ủy thác công việc cho 9 bean hạ tầng cốt lõi như HandlerMapping, HandlerAdapter và HttpMessageConverter. Cơ chế Auto-configuration tự động thiết lập toàn bộ hệ sinh thái này mà không cần cấu hình thủ công.

Vì sao Front Controller giải quyết triệt để hạn chế của Page Controller?

Trong kiến trúc Java EE truyền thống, mô hình Page Controller yêu cầu mỗi đường dẫn URL phải được ánh xạ tới một lớp servlet độc lập:

Plain Text
GET /orders         -> OrderListServlet.doGet()
POST /orders        -> OrderCreateServlet.doPost()
DELETE /orders/42   -> OrderDeleteServlet.doDelete()

Cách tiếp cận này bộc lộ ba điểm yếu lớn:

  1. Trùng lặp các mối quan tâm dùng chung (cross-cutting concerns): Mỗi servlet đều phải tự viết lại kiểm tra quyền truy cập, ghi log và xử lý ngoại lệ.
  2. Cồng kềnh cấu hình: File web.xml chứa hàng trăm dòng khai báo ánh xạ servlet phức tạp.
  3. Rất khó viết unit test: Do servlet bị gắn chặt vào servlet container nên khó có thể kiểm thử cô lập logic nghiệp vụ.

Cột trái bốn servlet, mỗi servlet lặp lại cùng một dòng auth log i18n; cột phải một Filter và Interceptor duy nhất đứng trước DispatcherServlet, sau đó tới controller là method Java thường

Mô hình Front Controller giải quyết triệt để vấn đề trên: một servlet duy nhất (DispatcherServlet) đứng ở cửa ngõ nhận mọi request. Các bộ lọc dùng chung được gắn phía trước, còn các phương thức xử lý nghiệp vụ trở thành những phương thức Java thuần túy (POJO) không còn phụ thuộc trực tiếp vào servlet API.

Bản chất hoạt động của DispatcherServlet và luồng doDispatch là gì?

DispatcherServlet kế thừa trực tiếp từ HttpServlet chuẩn của Java. Khi servlet container tiếp nhận request, phương thức service() sẽ chuyển tiếp đến hàm trung tâm doDispatch(request, response):

Chín bước của doDispatch xếp dọc: Tomcat gọi service, getHandler hỏi từng HandlerMapping, trả HandlerExecutionChain, chọn HandlerAdapter, chạy interceptor preHandle, adapter resolve tham số rồi gọi controller, HttpMessageConverter ghi JSON, cuối cùng postHandle và afterCompletion chạy theo thứ tự ngược

Quy trình 9 bước điều phối chuẩn xác:

  1. Servlet container (như Tomcat) nhận request và chuyển vào DispatcherServlet.doDispatch().
  2. Hàm getHandler(request) duyệt qua danh sách HandlerMapping để tìm kiếm controller method phù hợp.
  3. Trả về HandlerExecutionChain chứa method đích cùng danh sách các interceptor liên quan.
  4. getHandlerAdapter(handler) tìm kiếm adapter tương thích với loại controller được gọi.
  5. Thực thi phương thức preHandle() trên từng interceptor; nếu trả về false, chuỗi xử lý dừng lại ngay lập tức.
  6. Adapter giải nén tham số từ HTTP request và gọi thực thi method của controller.
  7. Controller xử lý logic và trả về dữ liệu kết quả (dạng object hoặc ResponseEntity).
  8. HttpMessageConverter chuyển đổi đối tượng trả về thành chuỗi JSON/XML trong thân HTTP response.
  9. Thực thi lần lượt postHandle() và afterCompletion() trên các interceptor theo chiều ngược lại.

9 bean hạ tầng nào cùng phối hợp trong DispatcherServlet?

Để đảm bảo nguyên lý Dependency Inversion, DispatcherServlet không tự xử lý toàn bộ công việc mà ủy nhiệm cho 9 bean hạ tầng:

Thành phần BeanChức năng chínhTriển khai mặc định trong Boot
HandlerMappingÁnh xạ URL và HTTP method tới controller methodRequestMappingHandlerMapping
HandlerAdapterĐiều phối gọi controller và giải nén tham sốRequestMappingHandlerAdapter
HandlerInterceptorCan thiệp trước và sau khi controller thực thiĐăng ký qua WebMvcConfigurer
HttpMessageConverterChuyển đổi thân HTTP body qua lại với Java objectMappingJackson2HttpMessageConverter
HandlerExceptionResolverBắt và chuyển đổi Exception thành HTTP responseExceptionHandlerExceptionResolver
ViewResolverPhân giải tên view cho ứng dụng MVC truyền thốngContentNegotiatingViewResolver
LocaleResolverXác định ngôn ngữ vùng miền từ request headerAcceptHeaderLocaleResolver
MultipartResolverPhân tích dữ liệu upload file đa phầnStandardServletMultipartResolver
ThemeResolverPhân giải giao diện người dùng (hiện đã deprecated)FixedThemeResolver

Khi một ngoại lệ xuất hiện trong controller, hệ thống chuyển giao cho chuỗi HandlerExceptionResolver để định dạng mã lỗi:

Exception từ controller đi lần lượt qua ExceptionHandlerExceptionResolver rồi ResponseStatusExceptionResolver rồi DefaultHandlerExceptionResolver, mỗi resolver bắt được thì trả status tương ứng; không cái nào khớp thì rơi xuống trang lỗi 500 mặc định

Spring Boot tự động cấu hình DispatcherServlet như thế nào?

Spring Boot tự động thiết lập toàn bộ hệ thống thông qua hai lớp auto-configuration:

DispatcherServletAutoConfiguration chịu trách nhiệm khởi tạo bean DispatcherServlet và đăng ký với Tomcat dưới đường dẫn "/":

Java
@AutoConfiguration
@ConditionalOnWebApplication(type = SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }
}

Kế đến, WebMvcAutoConfiguration nạp toàn bộ 9 bean hạ tầng đi kèm:

Java
@AutoConfiguration(after = DispatcherServletAutoConfiguration.class)
@ConditionalOnWebApplication(type = SERVLET)
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration {
    // Registers RequestMappingHandlerMapping, Jackson converters, etc.
}

Để thêm interceptor hoặc cấu hình CORS mà không làm mất các thiết lập mặc định, lập trình viên sử dụng giao diện WebMvcConfigurer:

Java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("https://olhub.vn");
    }
}

Điểm khác biệt mấu chốt giữa Servlet Filter và HandlerInterceptor là gì?

Cả hai đều có khả năng chặn bắt request nhưng hoạt động ở hai tầng kiến trúc hoàn toàn tách biệt:

Filter chain nằm ngoài khung DispatcherServlet nên chạy cho mọi request kể cả request sắp nhận 404; bên trong khung là HandlerMapping getHandler rồi interceptor preHandle rồi controller method, ba bước chỉ chạy khi URL đã khớp handler

Tiêu chí so sánhServlet FilterHandlerInterceptor
Tầng kiến trúcServlet API (nằm ngoài DispatcherServlet)Spring MVC (nằm trong DispatcherServlet)
Thời điểm thực thiChạy cho mọi request trước khi vào servletChỉ chạy sau khi URL đã khớp với controller
Nhận diện ControllerKhông biết method nào sẽ xử lýNhận đối tượng HandlerMethod cụ thể
Ngữ cảnh phù hợpXác thực Token, CORS, nén dữ liệuĐo lường thời gian controller, audit log

Những lỗi cấu hình kinh điển nào thường gặp với DispatcherServlet?

Dưới đây là các cạm bẫy cấu hình cần tránh:

  1. Thêm annotation @EnableWebMvc trong Spring Boot: Làm vô hiệu hóa hoàn toàn WebMvcAutoConfiguration, khiến ứng dụng mất bộ chuyển đổi Jackson JSON và trang lỗi mặc định.
  2. Dùng interceptor để xác thực bảo mật thay vì Filter: Khi client gửi request đến một đường dẫn 404 không tồn tại, interceptor sẽ không chạy, làm hở các lỗ hổng giám sát.
  3. Ghi đè nhầm configureMessageConverters: Phương thức này sẽ xóa sạch các converter mặc định của Spring Boot. Luôn dùng extendMessageConverters nếu chỉ muốn bổ sung converter mới.

Tóm tắt

  • DispatcherServlet hiện thực mẫu Front Controller, đóng vai trò cửa ngõ tập trung toàn bộ HTTP request.
  • Phương thức doDispatch() điều phối quy trình 9 bước từ tìm kiếm handler đến tuần tự hóa dữ liệu phản hồi.
  • 9 bean hạ tầng đảm nhiệm các tác vụ độc lập, giúp hệ thống dễ dàng mở rộng theo nguyên lý hướng đối tượng.
  • Mở rộng cấu hình tầng web an toàn bằng cách implement WebMvcConfigurer và tránh lạm dụng @EnableWebMvc.
  • Servlet Filter hoạt động ở tầng ngoài cùng của servlet container, trong khi HandlerInterceptor can thiệp sâu vào ngữ cảnh controller của Spring.

Tự kiểm tra

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Front Controller pattern trong Spring MVC giải quyết vấn đề cốt lõi nào của mô hình Page Controller cũ?
  2. Q2
    Điều gì sẽ xảy ra nếu lập trình viên khai báo thêm annotation @EnableWebMvc trong dự án Spring Boot thông thường?
  3. Q3
    Một request gửi tới URL không tồn tại (trả về lỗi 404). HandlerInterceptor đã đăng ký có được kích hoạt phương thức preHandle() không?
  4. Q4
    Thành phần bean hạ tầng nào chịu trách nhiệm chuyển đổi thân HTTP Request (JSON) thành Java Object trước khi gọi method controller?
  5. Q5
    Để đo thời gian thực thi của một controller method cụ thể kèm tên class và tên method, thành phần nào là lựa chọn tối ưu nhất?

Bài tiếp theo: URL Routing & Request Pipeline

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

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.

Lộ trình Junior Java Backend Developer

Chặng 15/21 · REST API với Spring MVC — bài 2/21 của chặng

Thảo luận & góp ý

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

Bài tiếp theo

URL Routing Pipeline: HandlerMapping Và PathPattern