- Model: 데이터에 대한 조회, 조작
- Controller: 어떤 요청을 받았을 때(= REST API = Method + URL), 어떤 웹 페이지를 반환할 것인가?
- 요청을 받고, 그에 따른 연산을 시작시키고, 그 결과를 반환시킨다.
- URI가 정의되어있다.(엔드포인트)
- View: 어떤 요청을 받았을 때(= REST API = Method + URL), 어떤 웹 페이지를 반환할 것인가?
- 유저가 보는 것: 웹 페이지 -> Controller가 반환해준 것
- 유저가 하는 것: 자바스크립트 인터렉션 -> Controller 호출
- 유저의 데이터(Model)를 바꿔달라는 요청을 View의 자바스크립트를 통해 Controller를 호출한다.
- 클라이언트가 요청을 보내면 서블릿 컨테이너가 요청을 받고 이를 디스패처 서블릿으로 전달합니다.
- 디스패처 서블릿은 Handler Mapping을 통해 요청 URL에 맞는 컨트롤러를 찾고,
- 가장 먼저 어떤 Controller가 요청을 처리할 수 있는지를 식별해야하는데, 이 역할을 하는 것이 Handler Mapping이다.
- 즉, Handler Mapping은 Dispatcher Servlet가 적합한 Controller 객체(Bean)을 찾는 역할
- 컨트롤러는 @Controller에 @RequestMapping 관련 어노테이션을 사용해 작성한다.
- 흔한 Controller 방식은 @Controller로 작성된 모든 컨트롤러를 찾고 파싱하여, Hashmap으로 <요청할 정보, 처리할 대상> 을 관리한다. 여기서 처리할 대상은 HandlerMethod 객체로 컨트롤러, 메소드 등을 가지고 있다. (스프링이 리플렉션을 이용해 요청을 위임하기 때문이다.)
- 그래서 요청이 오면 (Http Method, URI) 등을 사용해 요청 정보를 만들고, HashMap에서 요청을 처리할 대상(
Handler Method)를 찾은 후에 HandlerExcutionChain으로 감싸서 반환한다. 감싸는 이유는 컨트롤러로 요청을 넘겨주기 전에 처리해야하는 인터셉터 등을 포함하기 위해서이다.
- Handler Adapter를 통해 컨트롤러를 호출합니다.
- 디스패처 서블릿은 컨트롤러로 요청을 직접 위임하는 것이 아니라, Handler Adapter를 통해 위임한다. 이는 다양하게 작성되는 컨트롤러에 대응하기 위해서 스프링은 Handler Adapter라는 어댑터 인터페이스를 통해 어댑터 패턴을 적용함으로써 컨트롤러의 구현 방식에 상관없이 요청을 위임할 수 있도록 하였다.
- 즉, Handler Adapter는 Dispatcher Servlet이 찾았던 Controller 객체(Bean)에게 요청을 넘기는 역할
- Handler Apater가 컨트롤러로 요청을 위임한 전후에 공통적인 전/후 과정이 필요하다.
- 대표적으로 인터셉터들을 포함해 요청시에 @RequestParam, @RequestBody 등을 처리하기 위한 Argument Resolver들과 응답 시에 ResponseEntity의 Body를 Json으로 직렬화하는 등의 처리를 하는 Return Value Handler 등이 핸들러 어댑터에서 처리된다. Argument Resolver 등을 통해 파라미터가 준비되면 리플렉션을 이용해 컨트롤러로 요청을 위임한다.
- 컨트롤러가 요청(로직)을 처리하고 결과 데이터를 반환합니다.
- 컨트롤러는 서비스를 호출하고 서비스에서 우리가 작성한 비지니스 로직들이 진행된다.
- 비지니스 로직이 처리된 후에는 컨트롤러가 반환값을 반환한다.
- 응답 데이터를 사용하는 경우에는 주로 ResponseEntity를 반환하게되고, 응답 페이지를 보여주는 경우라면 String으로 View의 이름을 반환할 수도 있다.
- 만약 컨트롤러가 ResponseEntity를 반환하면 HttpEntityMethodProcessor가 MessageConverter를 사용해 응답 객체를 직렬화하고, 응답 상태(HttpStatus)를 설정한다.
- 만약 컨트롤러가 View 이름을 반환하면 ViewResolver를 통해 View를 반환한다.
- 디스패처 서블릿은 뷰 리졸버를 통해 논리적인 뷰 이름을 실제 뷰로 변환하고, 최종적으로 뷰를 렌더링하여 응답을 생성합니다.
- 생성된 응답이 서블릿 컨테이너를 통해 클라이언트로 전달됩니다.
- 디스패처 서블릿을 통해 반환되는 응답은 다시 필터들을 거쳐서 클라이언트에게 반환된다.
- 이때 응답이 데이터라면 그대로 반환되지만,
- 응답이 화면이라면 View의 이름에 맞는 View를 찾아서 반환해주는 ViewResolver가 적절한 화면을 전달한다.
Spring의 동작원리는 아래의 두가지 방법이 합쳐진다.
Tomcat의 Servlet Container를 통해서 유저 요청에 따른 Dispatcher Servlet을 할당한다.
Spring의 Spring Container를 통해 Dispatcher 요청에 따라 Spring Controller 할당.
Servlet Container
: 서블릿 컨테이너는 여러 서블릿을 관리하고 실행할 수 있는 환경을 제공하고, Spring Boot 애플리케이션에서는 이 서블릿 중 하나로 디스패처 서블릿(DispatcherServlet)이 등록되어 요청을 처리하게 된다.
Spring Container
:Spring Bean은 Spring Container로 관리되며 2개 타입의 ApplicationContext로 나뉜다.
- Servlet WebApplicationContext: 서블릿에서만 이용되는 Bean에 대한 Context
- Dispatcher Servlet이 직접 사용하는 컨트롤러를 포함한 웹 관련 Bean을 등록
- @Controller, HandlerMapping 등
- Root WebApplicationContext: 스프링 어디에서든 이용되는 Bean에 대한 Context
- 서비스 계층이나 DAO를 포함한 웹 환경에 독립적인 Bean을 등록
- @Service, @Repository 등
Dispatcher-Servlet
: HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아서 적합한 컨트롤러에 위임해주는 Front Controller라고 정의할 수 있다. 보다 자세하게 설명하자면, 클라이언트로부터 어떠한 요청이 오면 서블릿 컨테이너(Tomcat)가 요청을 받는다. 그리고 이 모든 요청을 디스패처 서블릿이 가장 먼저 받게된다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에, 해당 요청을 처리해야하는 컨트롤러를 찾아서 작업을 위임한다.
과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만, dispatcher servlet이 들어오는 모든 요청을 핸들링해주고, 공통 작업을 처리해주면서 상당히 편리해졌다. 즉, 우리가 컨트롤러를 구현해두기만하면 디스패처 서블릿이 알아서 적합한 컨트롤러로 위임을 해주는 구조가 되었다.
'Spring Boot' 카테고리의 다른 글
Spring JDBC (0) | 2024.11.29 |
---|---|
Spring MVC - Controller (0) | 2024.11.08 |
@어노테이션을 사용한 객체 생성 그리고 DTO (0) | 2024.10.04 |
Spring Bean (0) | 2024.10.04 |
8080 사용 중일 때 프로세스 죽이기 (0) | 2024.09.25 |