본문 바로가기

스프링

MVC, Spring MVC

MVC

MVC는 디자인 패턴 중 하나이다.

MVC는 Model, View, Controller의 약자로 하나의 애플리케이션의 구성요소를 세 가지의 역할로 구분한 패턴이다.

그림으로 살펴보면 다음과 같다.


(1) Model

  • Model은 애플리케이션이 무엇을 할 것인지를 정의한다.
  • Model은 DB의 역할과 같이 사용자가 필요한 데이터를 가지고 있다.
  • View나 Controller에 대한 정보는 알 수 없다.

(2) View

  • View는 사용자에게 무엇을 보여주기 위한 역할을 수행한다.
  • 컨트롤러 하위에 종속되어 모델이나 컨트롤러가 보여주려고 하는 모든 필요한 것들을 보여준다.

(3) Controller

  • Controller는 모델을 어떻게 처리하고 로직을 어떻게 처리할지를 정해 로직을 수행한다.
  • 사용자에게 입력을 받고 Model과 View의 중간에서 일을 수행한다.

스프링에서는 이와 같은 디자인 패턴을 채용하여 제공하는데 이를 Spring MVC라고 한다.

이에 대해 자세히 알아보자

Spring MVC

Spring MVC에서는 각 요청마다 각 컨트롤러를 호출하면서 생길 수 있는 비효율을 방지하기 위해 프론트 컨트롤러 패턴을 적용했다.

여기서 프론트 컨트롤러 패턴란, 공통의 로직을 관리하는 하나의 서블릿을 만들고 요청에 맞는 컨트롤러를 찾아 호출해주는 방법이다.

다음 그림에서 보면 DispatcherServlet을 통해 각각의 핸들러를 처리해줄 수 있는 핸들러 어댑터를 찾아 호출해주어 처리하고 있다.

아직은 이해가 안될수도 있으니 Spring MVC의 구조에 대해 그림과 함께 자세히 살펴보자.


Reqeust → DispatcherServlet

사용자는 서버에 요청을 하게되고 요청에 대한 request를 서버는 받게된다.


DispatcherServlet → HandlerMapping

DispatcherServlet은 해당 요청에 매핑된 핸들러(컨트롤러)를 조회한다.

해당 핸들러(컨트롤러)를 실행할 수 있는 핸들러 어댑터를 조회한다.

이것은 DispatcherServlet의 코드의 일부분이다.

다음과 같이 getHandler 메소드를 통해 handler들을 for문으로 돌려 맞는 핸들러가 있으면 찾아내고 아니면 null을 리턴한다.

null이 리턴되면 if문에서 noHandlerFound가 실행되는데 여기서 sc.not_found를 내보내 404 화면을 출력한다.


HandlerMapping → DispatcherServlet

조회한 결과, 해당 핸들러(컨트롤러)를 처리할 수 있는 핸들러 어댑터가 존재한다면 가져온다.

이것은 DispatcherServlet의 코드의 일부분이다.

다음과 같이 getHandlerAdapter을 통해 handlerAdapter들을 handler와 마찬가지로 for문으로 돌려 찾아낸다.

그런데 우리는 등록한 적이 없는데 핸들러와 핸들러어댑터는 어떻게 찾아지는 것일까?

스프링은 핸들러를 찾기위해 핸들러매핑 HandlerMapping 인터페이스와 그 구현체들을 구현해두었다.

몇 가지를 알아보면 다음과 같다.

  • RequestMappingHandlerMapping - @ReqeustMapping 애노테이션 기반
  • BeanNameUrlHandlerMapping - 빈 이름 기반
  • SimpleUrlHandlerMapping - favicon 요청처리

또한 스프링은 핸들러어댑터를 위해서 HandlerAdapter 인터페이스과 그 구현체들을 구현해두었다.

몇 가지를 알아보면 다음과 같다.

  • RequestMappingHandlerAdapter - @RequestMapping 애노테이션 기반
  • HttpReqeustHandlerAdapter - HttpRequestHandler 기반
  • SimpleControllerHandlerAdpater - 과거 Controller 인터페이스 기반

우리가 스프링에서 주로 컨트롤러를 등록하고 매핑하기 위해 사용하는 @Controller@RequestMapping이 실제로 RequestMappingHandlerMapping, RequestMappingHandlerAdapter를 사용하여 실행되는 것임을 여기서 확인할 수 있다.


DispatcherServlet → HandlerAdapter

조회한 핸들러 어댑터를 실행한다.


HandlerAdapter → Controller

실행된 핸들러 어댑터를 이용해 핸들러(컨트롤러)를 실행한다.

위의 그림에서 실제로 우리가 등록한 컨트롤러가 실행된다.


Controller → HandlerAdapter

실행된 결과로 뷰의 이름을 반환한다.


HandlerAdapter → DispatcherServlet

핸들러(Controller)의 결과값을 토대로 ModelAndView를 구성하여 반환한다.


DispathcerServlet → ViewResolver

각각에 맞는 ViewResolver를 찾고 이를 실행한다.


ViewResolver → DispatcherServlet

View의 이름(논리적)을 토대로 실제 위치(물리적)로 바꾸어 렌더링 역할을 하는 View를 반환한다.


ViewResolver → View

View를 통해 렌더링한다.


View → Response

렌더링된 결과를 반환한다.


마무리

Spring MVC는 이러한 방식으로 동작하게 되고 이러한 구조를 상당히 객체지향적으로 구현해놓았다.

우리는 단순히 이러한 구조를 신경쓰지 않고 개발하면 되는데 이러한 구조를 이해하고 한다면 더욱 Spring에 대한 이해도가 높아질 것이다.

이후에는 실제로 우리가 Spring MVC를 어떻게 다루는지에 대해서 알아보자.

'스프링' 카테고리의 다른 글

@RequestParam  (0) 2021.09.20
RequestMapping  (0) 2021.09.20
빈 초기화 콜백, 소멸전 콜백  (0) 2021.09.16
같은 타입의 빈 등록(중복)  (0) 2021.09.16
수동 빈 등록, 자동 빈 등록  (2) 2021.09.15