SPRING-HIBERNATE SERIES - BÀI 0.2

Hai List, Một Luật Chọn Đầu Tiên

LIST CÓ ĐÁY - KHUÔN MẶT SỐ 1 Đọc từ trái sang phải. Màu đậm dần nghĩa là gần cơ chế hơn. Dấu * đánh dấu điểm bài viết khai thác.

Triệu chứng A - thiếu @RequestBody

UserForm(name=null, email=null)

Cùng một gốcList chọn phần tử đầu tiên báo hỗ trợ; fallback hợp lệ che mất lời khai bị thiếu.

Triệu chứng B - thiếu @ResponseBody

return "ok" bị hiểu là tên view

Mức 1 - luồng sync phổ biến

DispatcherServlet.doDispatch()

Đường controller có annotation, không chạy async

  1. checkMultipart()Bọc request multipart nếu cần
  2. getHandler()Tìm HandlerExecutionChain
  3. getHandlerAdapter()Chọn adapter đầu tiên hỗ trợ handler
  4. applyPreHandle()Interceptor có thể dừng request
  5. ha.handle()Đi vào RequestMappingHandlerAdapter
  6. applyDefaultViewName()Bổ sung view mặc định khi cần
  7. applyPostHandle()Interceptor xử lý sau handler
  8. processDispatchResult()Giải exception, render và hoàn tất
  9. cleanupMultipart()Dọn tài nguyên ở nhánh đồng bộ
Mức 2 - zoom ha.handle()

RequestMappingHandlerAdapter

Chuẩn bị, gọi method, rồi diễn giải giá trị trả về

  1. handleInternal()Kiểm tra request và session policy
  2. invokeHandlerMethod()Dựng ngữ cảnh gọi controller
  3. getDataBinderFactory()Chuẩn bị binding và conversion
  4. getModelFactory()Khởi tạo model và session attributes
  5. createInvocableHandlerMethod()Gắn argument resolvers và return handlers
  6. modelFactory.initModel()Nạp model trước khi gọi controller
  7. getMethodArgumentValues()List argument resolver chọn người xử lý - mở ra nhánh A bên phải
  8. doInvoke()Gọi method với arguments đã đúc
  9. handleReturnValue()List return handler diễn giải kết quả - mở ra nhánh B bên phải
  10. getModelAndView()Trả kết quả về DispatcherServlet
Mức 3 - zoom 2 điểm chọn

First match wins, rồi được cache

Trích đúng đoạn thứ tự quyết định 2 triệu chứng

A. Argument resolver

HandlerMethodArgumentResolverComposite.getArgumentResolver()

  1. RequestParamMethodArgumentResolver(false)Chỉ nhận lời khai phù hợp
  2. ServletModelAttributeMethodProcessor(false)Nhận @ModelAttribute
  3. RequestResponseBodyMethodProcessorChỉ nhận @RequestBody và đọc body
  4. Các resolver annotation và type khácSau đó mới tới custom resolvers
  5. PrincipalMethodArgumentResolverBắt đầu nhóm catch-all
  6. RequestParamMethodArgumentResolver(true)Nhận kiểu đơn giản không annotation
  7. ServletModelAttributeMethodProcessor(true)Nhận object phức tạp, bind request parameters; JSON body không được converter đọc

B. Return value handler

HandlerMethodReturnValueHandlerComposite.selectHandler()

  1. Các handler kiểu trả về chuyên biệtModelAndView, ResponseEntity, async và streaming
  2. ServletModelAttributeMethodProcessor(false)Nhận @ModelAttribute
  3. RequestResponseBodyMethodProcessorNhận @ResponseBody hoặc @RestController
  4. ViewNameMethodReturnValueHandlerString không lời khai trở thành view name
  5. MapMethodProcessor và custom handlersChạy trước catch-all cuối
  6. ServletModelAttributeMethodProcessor(true)Fallback cuối nếu không có ModelAndViewResolver

Kiểm chứng đúng lúc

Đặt breakpoint tại getArgumentResolver(), rồi restart app hoặc gọi endpoint chưa chạy. Sau lần chọn đầu, resolver được lưu trong argumentResolverCache; request sau thường không đi qua vòng for.

Lối ra theo đúng hợp đồng

  • JSON requestThêm @RequestBody để dừng tại body processor.
  • REST responseDùng @ResponseBody hoặc @RestController để ghi response body.

Khi KHÔNG được kết luận

  • Object nhận vào rỗngChưa đủ để kết luận thiếu annotation; body rỗng, key sai hoặc binder tùy biến cũng có thể gây triệu chứng.
  • String bị tìm như viewChưa đủ để kết luận controller thiếu annotation; method có thể chủ ý trả view, còn view resolver vẫn cần được kiểm tra.