초기 요청 흐름
클라이언트로부터 http 요청이 들어오면, 웹 애플리케이션 서버는 이를 DispatcherSevlet으로 전달한다.
- 서블릿이 호출되면 DispatcherServlet의 부모 클래스 FrameWorkServlet에서
HttpServlet의 service()을 오버라이드한 메소드가 실행된다. - FrameWorkServlet.service() 호출을 시작으로, 여러 메소드들이 실행되면서 제일 중요한 DispatcherServlet.doDispatch()가 실행된다.
DispatcherServlet.doDispatch() 코드 요약
- getHandler() 호출로 요청에 맞는 핸들러 얻어옴
- getHandlerAdapter()로 요청에 맞는 핸들러 어댑터 얻어옴
- 핸들러 어댑터.handle() 실행
- @RequestMapping("요청url") 어노테이션이 붙어있는 핸들러(컨트롤러) 실행
- 핸들러 어댑터에서 디스패처 서블릿으로 ModelAndView 객체 반환
- resolveViewName() 을 통해 viewResolvers를 순회하며 view를 생성할 수 있는 적합한 뷰 리졸버를 찾고, 생성한 뷰를 반환함
전체 흐름 요약
1. 요청 수신 - 클라이언트의 http 요청을 WAS가 수신하고, 이를 DispatcherServlet으로 전달
2. 핸들러 매핑 - 요청을 처리할 적절한 핸들러를 찾음
3. 핸들러 어댑터 매핑 - 찾은 핸들러를 실행할 수 있는 핸들러 어댑터를 찾음
4. 핸들러 실행 - 핸들러 어댑터를 이용해 핸들러 실행
5. 뷰 리졸버 - 핸들러가 반환한 뷰 이름을 바탕으로, 뷰를 생성할 수 있는 뷰 리졸버 찾음
6. 뷰 리졸버가 반환한 뷰 객체를 사용하여 DispatcherServlet이 모델 데이터를 포함한 응답 컨텐츠 생성 후 전송
스프링은
핸들러 매핑, 핸들러 어댑터, 뷰 리졸버, 뷰
모두 인터페이스로 만들어 두었다.
다음 설명할 RequestMappingHandlerMapping이나 RequestMappingHandlerAdapter 등은 모두
인터페이스를 구현한 클래스들인 것이다.
핸들러 매핑 & 핸들러 어댑터 로직
다음은 스프링 부트가 자동 등록하는 핸들러 매핑과 핸들러 어댑터이다.
0부터 우선순위가 제일 높다. 이는 찾을 때 0순위 먼저 체크해본다는 뜻이다.
HandlerMapping
0 = RequestMappingHandlerMapping
설명: 요청에 맞는 url을 가진 (ex. @RequestMapping("url")) 애노테이션.이 붙은 핸들러를 찾는다
1 = BeanNameUrlHandlerMapping
설명: 스프링 빈의 이름으로 핸들러를 찾는다.
...
HandlerAdapter
0 = RequestMappingHandlerAdapter
설명: 애노테이션 기반의 컨트롤러를 처리하는 데 필요한 핸들러어댑터
1 = HttpRequestHandlerAdapter
설명: HttpRequestHandler를 처리하는 데 필요한 어댑터
...
HandlerMappings를 순회하며 핸들러 조회
HandlerMapping 리스트를 순회하면서 핸들러 request에 맞는 핸들러를 찾고,
null이 아니면(찾았으면) 그 핸들러를 반환한다.
// doDispatch() 내부에서 호출하는 getHandler() 코드 발췌
// 이 코드 위에 private List<HandlerMapping> handlerMappings; 선언되어있음
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next(); // 이때 0순위부터 mapping에 대입됨
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
HandlerAdapters를 순회하며 핸들러 어댑터 조회
HandlerAdapter 리스트를 순회하면서 support(handler)가 true인 어댑터를 찾고 반환
//getHandlerAdapter() 발췌
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next(); // 이때 0순위부터 대입됨
if (adapter.supports(handler)) {
return adapter;
}
}
❗ ! 다시한번 상기 HandlerMapping과 HandlerAdapter는 인터페이스이다.
RequestMappingHandlerMapping, BeanNameUrlHandlerMapping 등은
HandlerMapping을 구현한 클래스인 것이다.
가장 우선순위가 높은 핸들러 맵핑과 핸들러 어댑터는
RequestMappingHandlerMapping, RequestMappingHandlerAdapter 이다.
'Spring' 카테고리의 다른 글
@NotNull과 nullable = false, 뭐가 다를까? ✍️ (1) | 2025.02.28 |
---|---|
AOP: 횡단관심사와 애스펙트 (0) | 2024.07.17 |
핸들러 "어댑터"를 쓰는 이유 (0) | 2024.07.05 |
HttpHeaders, HttpEntity, ResponseEntity, RequestEntity (0) | 2024.06.18 |
스프링 부트 자동 설정 (AutoConfiguration.imports) 과 DispatcherServlet (0) | 2024.05.23 |
서블릿에서 JSP, 이어서 MVC 패턴이 사용되기까지 (0) | 2024.05.20 |