결국 무엇이든 해내는 사람

Spring Container? Spring MVC? Dispatcher Servlet 쉽게 쉽게 알아보자 본문

본격적인 공부 노트/Spring

Spring Container? Spring MVC? Dispatcher Servlet 쉽게 쉽게 알아보자

kkm8257 2024. 2. 18. 23:35
반응형

 

서블릿 컨테이너와 스프링 컨테이너

 

Spring Container는 Bean 생명 주기를 관리한다. 

"Spring Container = DI Container" 로 생각하자.

Bean을 관리하기 위해 IoC가 이용되며 BeanFactor 객체가 바로 IoC 컨테이너(=DI 컨테이너, 스프링 컨테이너)이다.

이 IoC 컨테이너를 상속하면서 부가 기능을 추가한 것이 ApplicationContext이다.

위 그림대로 Spring Container는 Servlet Container 안에 존재하는 것을 확인 할 수 있다. 

즉, Spring Container는 Servlet Container와 독립적인 존재가 아니며 Servlet Container가 Spring Bean에 접근하려면 Spring Conatiner를 거쳐야한다.

 

 

Spring MVC가 뭔데?


Spring MVC란 프론트 컨트롤러 패턴에 기초한 웹 MVC 프레임워크이다. Spring 프레임워크의 하위 모듈이며, Model, View, Controller를 명확하게 분리하여 매우 유연하고 확장성이 좋다는 특징이 있다.

 

 

Spring MVC가 없을 때는?


Spring MVC가 없던 과거에는, URL마다 서블릿을 생성하고 Web.xml로 서블릿을 관리했다. URL마다 서블릿이 필요하다 보니, 매번 서블릿 인스턴스를 만들어야했다. 또한, 각 서블릿마다 공통 기능을 하는 코드들이 중복해서 발생하여 유지 보수 하기 어려웠다.

 

 

과거

 

 

프론트 컨트롤러 패턴


 

프론트 컨트롤러 패턴은 모든 요청을 프론트 컨트롤러(하나의 서블릿)에게 보내고, 프론트 컨트롤러는 각 요청에 맞는 컨트롤러를 찾아서 호출하는 역할을 한다. 그래서 공통 기능은 프론트 컨트롤러에서 처리하고, 서로 다른 코드들만 각 컨트롤러에서 처리하도록 할 수 있다.
 

 

 

DispatcherServlet 이란?


 

"HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러"이다.

작업흐름을 알아보자. (먼저 "Servlet Container"를 "Tomcat"과 같다고 생각하자)

 

클라이언트로부터 요청이 들어오면 Tomcat과 같은 "Servlet Container"가 요청을 받게 된다.

그리고 이 요청은  "Servlet Container"내의 "Dispatcher Servlet"이 가장 먼저 받게된다.

그러면 "Dispatcher Servlet"은 공통적인 작업을 먼저 처리한 후에 "해당 요청을 처리해야하는 컨트롤러를 찾아서 작업을 위임"한다

이 때 사용되는 용어가 "프론트 컨트롤러"이고 "Dispatcher Servlet"는 "Servlet Container"의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러라고 정의 할 수 있는 것이다.

 

 

Dispatcher Servlet의 장점


Spring MVC는 Dispatcher Servlet이 등장함에 따라 web.xml의 역할을 상당히 축소시켜주었다.

과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만, Dispatcher Servlet이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리면서 상당히 편리하게 이용할 수 있게 되었다.

우리는 컨트롤러를 구현해두기만 하면 Dispatcher Servlet이 알아서 적합한 컨트롤러로 위임을 해주는 구조가 되었다.

 

 

 

Dispatcher Servlet의 동작 순서


 

 

1. 클라이언트의 요청을 디스패처 서블릿이 받음

서블릿 컨텍스트(웹 컨텍스트)에서 필터들을 지나 스프링 컨텍스트에서 디스패처 서블릿이 가장 먼저 요청을 받게된다.

 


2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음

디스패처 서블릿은 요청을 처리할 핸들러(컨트롤러)를 찾고 해당 객체의 메소드를 호출한다.

따라서 가장 먼저 어느 컨트롤러가 요청을 처리할 수 있는지를 식별해야 하는데, 해당 역할을 하는 것이 바로 HandlerMapping이다.

최근에는 @Controller에 @RequestMapping 관련 어노테이션을 사용해 컨트롤러를 작성하는 것이 일반적이지만

예전 스펙을 따라 Controller 인터페이스를 구현하여 컨트롤러를 작성할 수도 있다.

즉, 컨트롤러를 구현하는 방법이 다양하기 때문에 스프링은 HandlerMapping 인터페이스를 만들어두고, 다양한 구현 방법에 따라 요청을 처리할 대상을 찾도록 되어 있다.
 

3. 요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달함

이후에 컨트롤러로 요청을 위임해야 하는데, 디스패처 서블릿은 컨트롤러로 요청을 직접 위임하는 것이 아니라 HandlerAdapter를 통해  위임한다. 

그 이유는 앞서 설명하였듯 컨트롤러의 구현 방식이 다양하기 때문이다.
그래서 다양하게 작성되는 컨트롤러에 대응하기 위해 스프링은 HandlerAdapter라는 어댑터 인터페이스를 통해 어댑터 패턴을 적용함으로써 컨트롤러의 구현 방식에 상관없이 요청을 위임할 수 있도록 하였다.

과거에는 Controller를 인터페이스로 구현하였는데 향후에 어노테이션 기반으로 구현할 수 있도록 도입하였다고한다.
 

4. 핸들러 어댑터가 컨트롤러로 요청을 위임함

핸들러 어댑터가 컨트롤러로 요청을 위임한 전/후에 공통적인 전/후처리 과정이 필요하다.

대표적으로 인터셉터들을 포함해 요청 시에 @RequestParam, @RequestBody 등을 처리하기 위한 ArgumentResolver들과 

응답 시에 ResponseEntity의 Body를 Json으로 직렬화하는 등의 처리를 하는 ReturnValueHandler 등이 핸들러 어댑터에서 처리된다.

ArgumentResolver 등을 통해 파라미터가 준비 되면 리플렉션을 이용해 컨트롤러로 요청을 위임한다.

5. 비지니스 로직을 처리함

개발자가 작성한 비즈니스 로직 수행


6. 컨트롤러가 반환값을 반환함

비지니스 로직이 처리된 후에는 컨트롤러가 반환값을 반환한다.

응답 데이터를 사용하는 경우에는 주로 ResponseEntity를 반환하게 되고, 응답 페이지를 보여주는 경우라면 String으로 View의 이름을 반환할 수도 있다.

7. 핸들러 어댑터가 반환값을 처리함


8. 서버의 응답을 클라이언트로 반환함
디스패처 서블릿을 통해 반환되는 응답은 다시 필터들을 거쳐 클라이언트에게 반환된다.

이때 응답이 데이터라면 그대로 반환되지만, 응답이 화면이라면 View의 이름에 맞는 View를 찾아서 반환해주는 ViewResolver가 적절한 화면을 내려준다.

 

 

 

 

반응형
Comments