Spring MVC의 동작 방식을 포스팅하려고 한다. WAS의 서블릿 컨테이너의 기능에 대해서는 간략하게 설명할 것이다.
Spring MVC(Spring Web MVC)는 스프링 프레임워크의 일부로 모델-뷰-컨트롤러 아키텍처를 구현한다. Spring MVC는 DispatcherServlet을 중심으로 동작이 설계되고 DispatcherServlet은 동작을 앞단에서 제어한다고 해서 FrontController라고도 한다.
Spring MVC 구조
다음은 Spring MVC의 구조로 컨트롤러 이후의 비즈니스 로직과 DB 로직은 제외했다.
Spring MVC는 웹 요청을 실제로 처리하는 객체를 핸들러라고 한다. 이는 웹 요청은 보편적으로 사용되는 @Controller 외에도 직접 만든 클래스를 이용해서 클라이언트의 요청을 처리하거나 Controller 인터페이스를 구현해서 요청을 처리할 수 있기 때문에 핸들러라고 표현한다.
Spring MVC 동작 순서
Spring MVC의 동작 순서는 그림과 같이 진행되며 웹 브라우저에 요청이 들어오고 DispatcherServlet에 전달되기전 까지는 서블릿 컨테이너에서 동작하며 이후 DispatcherServlet으로 요청이 전달된 이후부터는 스프링 컨테이너가 요청을 제어한다.
1. HTTP 요청
웹 브라우저(클라이언트)의 요청이 톰캣과 같은 WAS로 들어온다.
수신된 요청에서 URL, HTTP Method, Header, Cookie, Body 등의 정보를 파싱해서 HttpServletRequest를 생성한다. 여기서 서블릿이 메모리에 로딩되어 있지 않다면 클래스 로더를 사용해서 서블릿 클래스가 메모리에 로드된다.
이렇게 생성된 HttpServletRequest는 DispatcherServlet으로 전달되게 되고, 이 과정에서 설정된 필터들이 있다면 실행되게 된다.
2. 요청 URL과 매칭되는 핸들러 조회
DispatcherServlet(FrontController)은 웹 요청의 모든 연결을 담당한다.
DispatcherServlet은 요청을 처리하기 위한 컨트롤러 객체를 검색하는데, 이 때 직접 검색하는 것이 아닌 HandlerMapping이라는 빈 객체에게 검색을 위임한다. 우리가 주로 사용하는 @Controller 애노테이션을 적용한 컨트롤러는 RequestMappingHandlerMapping 에게 요청을 처리할 수 있는 핸들러의 메서드를 찾도록 요청한다.
RequestMappingHandlerMapping은 HttpServletRequest에서 요청 정보를 기준으로 적절한 핸들러 메소드를 탐색한다. 요청과 일치하는 핸들러 메서드를 찾으면 컨트롤러 객체, 메서드, 메서드 파라미터 정보 등을 담는 HandlerMethod 객체를 생성한다. 이 객체는 후에 HandlerAdapter가 정확한 핸들러를 실행하게 해준다.
RequestMappingHandlerMapping은 생성한 HandlerMethod를 DispatcherServlet에게 반환한다.
3. 핸들러 처리를 위한 핸들러 어뎁터 조회
DispatcherServlet은 컨트롤러의 객체 실행을 직접 하지 않는다.
DispatcherServlet은 @Controller 애노테이션을 이용한 컨트롤러, Controller 인터페이스를 구현한 컨트롤러 등을 구현한 클래스를 동일한 방법으로 실행할 수 있는데, 이 때 사용되는 것이 HandlerAdapter 스프링 빈 객체다.
DispatcherServlet은 HandlerMethod의 정보를 기반으로 HandlerAdapter 빈을 순회하면서 핸들러를 처리할 수 있는 HandlerAdapter를 찾는다. supports(Object handler) 메서드를 통해서 핸들러를 처리할 수 있는지 확인하고 처리 가능한 HandlerAdapter를 반환한다.
4. 처리 요청
DispatcherServlet은 찾은 HandlerAdapter에 요청의 처리를 위임한다.
5. 핸들러 실행
HandlerAdapter 컨트롤러의 메서드를 호출해서 요청을 처리해야 한다. 이 때 요청의 전/후로 파라미터를 ArgumentResolver를 사용해서 @RequestParam, @ModelAttribute, @RequestBody 등의 파라미터 및 HTTP 메시지를 처리한다.
6. 결과 반환
핸들러는 요청을 처리해서 결과를 반환한다. 이 때 요청을 처리할 때는 Service Layer와 Persistence Layer를 통한 비즈니스 로직 처리가 이뤄진다.
7. ModelAndView 반환
DispatcherServlet은 핸들러 객체의 실제 타입에 상관없이 결과를 ModelAndView로 받을 수 있으면 된다. 핸들러의 실제 구현 타입에 따라서 ModelAndView를 반환할 수도 있고, 아닐 수도 있는데 HandlerAdapter가 핸들러의 처리 결과를 ModelAndView로 변환해서 반환한다. ModelAndView에는 이름 그대로 View의 이름과 렌더링에 필요한 Model 데이터를 가지고 있다.
8. ViewResolver를 호출해서 View 검색
DispatcherServlet은 요청 처리 결과를 ModelAndView로 받으면 결과를 출력할 View를 찾기위해서 ViewResolver 빈 객체를 사용한다.
9. View 반환
ViewResolver는 ModelAndView에 있는 뷰 이름으로 View를 찾아서 반환한다.
10. 응답 View 생성
DispatcherServlet은 ViewResolver가 반환한 View 객체에게 응답 결과 생성을 요청하고, 뷰 객체는 Model 데이터를 사용해서 데이터를 매핑해서 최종 HTML 페이지를 생성한다.
11. HTTP 응답
생성된 HTML 페이지를 웹 브라우저에게 응답한다.
이번엔 Spring MVC의 동작 구조 및 순서별 동작 방식을 정리했는데 각 과정별 자세한 동작과정을 연관된 클래스의 로직을 보면서 확인해보면 좀더 깊게 이해할 수 있을 것 같다.
'Spring' 카테고리의 다른 글
Spring Rest Docs 사용하기 (3) | 2024.08.23 |
---|---|
[Spring Batch] JobParameters와 검증(JobParametersValidator) (3) | 2024.07.21 |
[Spring Batch] Chunk 지향 처리 (1) | 2024.07.19 |
[Spring Batch] 스프링 배치 메타데이터 스키마 확인 (2) | 2024.07.14 |
[Spring Batch] 스프링 배치 개념 및 사용해보기 (0) | 2024.07.14 |