본 글의 목적은 클라이언트에서 웹 요청을 했을 때
Spring famework에서 어떤 과정을 통해 응답을 하는지
러프한 흐름을 알아보는 것이다.
즉 다음 그림의 흐름이 무엇인지 이해하는 것이다
이 과정을 위해 먼저 알아봐야할 개념이 있다.
DispatcherServlet가 그것이다.
1. DispatcherServlet
디스패처 서블릿은 서블릿의 일종이다
그럼 서블릿이란 무엇일까?
서블릿의 간편 정의
" 클라이언트의 요청을 처리하고 그 결과를 반환하는 프로그램"
예를 들어 다음과 같은 HTTP 요청과 응답이 있다고 가정하자
|
|
HTTP Request | HTTP Response |
다음 예시는 매우 간단하지만 실제로는 여러 사용자가 더 복잡한 요청을 보내올 것이다.
이 요청들을 개발자가 직접 해석하고 처리한다면, 개발자의 목과 허리가 남아나지 않을 것이다.
따라서, 우리는 서블릿이라는 프로그램을 통해 요청 메세지를 읽고 응답을 만들어준다.
이는 개발자는 비즈니스 로직만 집중할 수 있도록 도와준다는 것을 의미한다.
Servlet의 간단 동작 방식을 예를 들면 다음과 같다.
1. 사용자가 URL을 입력하면 HTTP Request가 Servelet Container로 전송된다.
2. 서블릿 컨테이너는 HttpRequest와 HttpResponse를 생성한다.
3. 사용자의 요청 URL이 어느 서블릿 요청인지 찾는다.
4. service 메서드 호출 후, 클라이언트의 HTTP method에 따라 Controller에게 작업을 위임한다.
5. 동적 페이지를 생성한 후 HttpServeletResponse 객체에 응답을 보낸다.
6. 응답 후 HttpServletRequest, HttpServletResponse 객체를 소멸한다
그럼 서블릿의 일종인 디스패처 서블릿이란 무엇일까?
디스패처 서블릿은 그중 Http 프로토콜을 통해 들어오는 모든 요청을 중앙 집중식으로 처리하는 프론트 컨트롤러이다.
프론트 컨트롤러 도입 전 | 프론트 컨트롤러 도입 후 |
그림 출처 : https://yoonbing9.tistory.com/79
여기서 프론트 컨트롤러란 Spring MVC 디자인 패턴의 일종으로 컨트롤러 앞에서 수문장 역할을 하며 공통 영역을 처리해주는 패턴을 의미한다.
즉, 프론트 컨트로러인 디스패처 서블릿을 요약하자면
클라이언트의 Http 요청을 가장 먼저 받아 공통작업을 처리하고 응답해주는 프로그램이다.
동작 흐름 파헤치기
이제 본격적으로 동작흐름을 알아보자
1) DispathcerServlet으로 클라이언트의 웹 요청(HttpServletRequest)가 들어온다.
- 이때 filter를 통해 요청에 대해 전처리 작업(원하는 형태로 변형)을 사전에 수행할 수 있다
- DispatcherServelet이 웹 요청을 연동 인터페이스 구현체에서 분석한다 |
> DispatcherServelet 연동 인터페이스 정보
2) 웹 요청을 HandlerMapping 에 위임하여 요청을 처리할 Handler를 탐색한다.
- Handler란 클래스 관점에서는 Controller이다
- 즉 HandlerMapping은 요청에 적합한 컨트롤러를 찾는 과정이다.
예를 들어 다음과 같은 코드가 있다고 가정하자
@RestController
public class ReservationController {
@GetMapping("reservations")
public ResponseEntity<List<ReservationResponseDto>> reservations() {
List<ReservationResponseDto> reservations = ReservationResponseDto.listOf(reservationService.getAllReservations());
return ResponseEntity.ok(reservations);
}
}
여기서는 GET 요청의 reservations 라는 요청에 대해 reservations() 메서드가 메핑된다.
즉, 요청을 처리할 진입점인 컨트롤러가 ReservationController라는 사실을 판단한다.
그 매핑을 판단해주는 것이 HandlerMapping 클래스이다.
3) 찾은 Handler를 실행가능한 HandlerAdapter를 탐색한다.
HandlerMapping은 Controller를 찾는 역할을 한다.
이제 실제 실행을 위해 메서드를 호출하는 역할을 하는 Adapter가 필요하다.
4/5) 찾은 HandlerAdapter를 이용하여 Handler의 메소드를 실행한다.
=> 이때 반환값은 Model과 View이다.
RequestMappingHandlerAdapter 클래스는 핸들러 메서드에
매개변수를 전달하고 메서드의 처리결과를 반환 값으로 되돌려 보낸다.
앞선 코드를 예시로 보자
@RestController
public class ReservationController {
@GetMapping("reservations")
public ResponseEntity<List<ReservationResponseDto>> reservations() {
List<ReservationResponseDto> reservations = ReservationResponseDto.listOf(reservationService.getAllReservations());
return ResponseEntity.ok(reservations);
}
}
Mapping 클래스를 통해 진입점을 파악한 Adapter는
ReservationController의 reservations() 메서드를 실행한다.
비즈니스 로직을 실행한 이후 ResponseEntity를 반환한다.
이 ResponseEntity에는 header, body, Http Status 코드가 포함되어 있다.
다만 이 @RestController에서는 Model이 유일하고
@Controller에는 Model과 View과 모두 반환된다.
여기서는 일반 컨트롤러를 기준으로 과정을 이어가보자
6) View 이름을 ViewResolver에게 전달하고 해당하는 View 객체를 반환한다
ViewResolver는 말 그대로 뷰의 이름을 통해 실제 뷰를 매핑하는 기능을 제공한다.
메서드의 파일의 경로가 포함된 메서드를 정의하면
ViewResolver가 경로를 통해 실제 뷰를 브라우저에 렌더링할 수 있도록 도와준다.
7) DispatcherServlet이 View를 렌더링한다.
- DispatcherServlet은 View에게 Model을 전달하고 화면 표시를 요청한다.
- 만약 Model이 null이면 View를 그대로 사용한다.
- Model에 값이 있으면 View에 Model 데이터를 렌더링한다.
8) 최종적으로 view의 결과(HttpServletResponse)를 클라이언트에게 전달한다.
여기까지가 웹 요청/응답을 framework 입장에서 기술한 것이다.
이제 전체 흐름도를 보고 직접 설명할 수 있을 정도까지 익혀보자!
reference)
https://tecoble.techcourse.co.kr/post/2021-05-23-servlet-servletcontainer/
https://yoonbing9.tistory.com/79
https://mungmange.tistory.com/129
https://mingyum119.tistory.com/304
'우테코' 카테고리의 다른 글
[Rest Docs vs Swagger] 1편 : Rest Docs로 API 문서 자동화해보기 (0) | 2024.06.13 |
---|---|
[Spring] 유효성 검사 (0) | 2024.05.11 |
우테코 4주차- [크리스마스 이벤트] 회고 (0) | 2023.11.15 |
우테코 4주차 - [크리스마스 이벤트] 프로그래밍 요구사항 및 기능목록 작성 (0) | 2023.11.15 |
우테코 4주차 - 3주차 공통 피드백 검토 (0) | 2023.11.11 |