Spring MVC Framework란?
MVC는 Model-View-Controller의 약자로 하나의 디자인 패턴을 뜻한다. Spring MVC에 대해 이해하려면 Model, View, Controller에 대한 이해가 필수이니 해당 내용에 대해 잘 모른다면 다음을 참고하자.
Spring MVC Framework는 웹 애플리케이션을 빌드하기 위한 프레임워크이다.
다른 MVC Framework 들도 웹 어플리케이션을 빌드할 수 있다. 하지만 Spring MVC는 MVC 디자인 패턴을 따르며 Spring Framework의 특징인 의존관계 주입(DI), 제어의 역전(IoC) 등을 구현한다.
위 사진의 구조와 역할을 간단히 살펴보면, 프론트 컨트롤러(Front Controller)가 우선적으로 클라이언트로부터 모든 요청을 받게 되며, 실제 요청의 처리는 개별 컨트롤러 클래스로 위임을 한다.( 일종의 중앙처리장치와 같은 것으로 요청이 들어오면 WAS가 개별 서블릿에 해당 요청에 대한 처리를 위임하는 논리와 비슷하다 )
개별 컨트롤러 클래스는 핸들러(Handler)라고도 하며, DI를 통해 생성해둔 Bean을 통해 비즈니스 로직 처리 결과를 Model에 담아 다시 프론트 컨트롤러로 보낸다. 프론트 컨트롤러는 받은 Model을 알맞은 View 템플릿으로 전달하여 반영시키고, 최종적으로 클라이언트로 보낼 화면을 응답 결과로 전송하는 것이다.
프론트 컨드롤러(Front Controller)에 대한 내용은 아래 포스팅 참고.
Spring MVC 실제 동작 구조
DispatcherServlet
- 사용자의 모든 요청을 받아 처리한다.
- 프론트 컨트롤러에 해당하는 역할을 수행하며 Request를 각각의 Controller에게 위임한다.
- DispatcherServlet을 Front Controller로 가능하도록 설정하기 위해서는 이를 web.xml에 명시하거나 org.springframework.web.WebApplicationnlnitializer 인터페이스를 구현하는 두 가지 방식을 사용할 수 있다.
HandlerMapping
- 요청을 직접 처리할 컨트롤러를 탐색한다.
- 구체적인 mapping은 xml파일이나 java config 관련 어노테이션 등을 통해 처리할 수 있다.
HandlerAdapter
- 매핑된 컨트롤러의 실행을 요청한다.
Handler(Controller)
- Spring MVC에서는 Controller=Handler(핸들러)라고 생각하면 편하다. 핸들러는 DispatcherServlet가 전달해준 HTTP 요청을 처리하고 결과를 Model에 저장한다.
- 여기서 결과가 반환되면 HandlerAdapter가 ModelAndView 객체로 변환되며, 여기에는 View Name과 같이 응답을 통해 보여줄 View에 대한 정보와 관련된 데이터가 포함되어 있다.
View Resolver
- View Name을 확인한 후, 실제 컨트롤러로부터 받은 로직 처리 결과를 반영할 View 파일(jsp)을 탐색한다.
View
- 로직 처리 결과를 반영한 최종 화면을 생성한다.
MVC 패턴 동작 순서
- 클라이언트가 서버에 요청을 하면, front controller인 DispatcherServlet 클래스가 요청을 받는다.
- DispatcherServlet은 프로젝트 파일 내의 servlet-context.xml 파일의 @Controller 인자를 통해 등록한 요청 위임 컨트롤러를 찾아 메핑(mapping)된 컨트롤러가 존재하면 @RequestMapping을 통해 요청을 처리할 메소드로 이동한다.
- 컨트롤러는 해당 요청을 처리한 Service(서비스)를 받아 비즈니스 로직을 서비스에게 위임한다.
- Service(서비스)는 요청에 필요한 작업을 수행하고, 요청에 대해 DB에 접근해야한다면 DAO에 요청하여 처리를 위임한다.
- DAO는 DB정보를 DTO를 통해 받아 서비스에게 전달한다.
- 서비스는 전달받은 데이터를 컨트롤러에게 전달한다.
- 컨트롤러는 Model(모델) 객체에게 요청에 맞는 View(뷰) 정보를 담아 DispatcherServlet에게 전송한다.
- DispatcherServlet은 ViewResolver에게 전달받은 View 정보를 전달한다.
- ViewResolver는 응답할 View에 대한 JSP를 찾아 DispatcherServlet에게 전달한다.
- DispatcherServlet은 응답할 뷰의 Render를 지시하고 뷰는 로직을 처리한다.
- DispatcherServlet은 클라이언트에게 Rending된 뷰를 응답하며 요청을 마친다.
HandlerMapping과 Handler Adapter
핸들러 매핑은 DispatcherServlet이 요청에 맞는 핸들러를 찾는 과정이다. 핸들러 어댑터는 핸들러 매핑에서 찾은 핸들러 객체를 다룰 수 있는 어댑터이다.
핸들러 매핑에서 요청에 맞는 핸들러를 찾았으면 바로 핸들러를 호출하면 되는 게 아닌가 하는 의문이 들 수 있다.
핸들러의 return 타입은 String, ModelAndView 등 다양하며, Parameter로 들어오는 값도 HttpServletRequest로 받거나 HttpServletResponse로 받는 등 다양한 형식으로 받을 수 있다. 이처럼 다양한 핸들러 구현 방식에 맞춰 개발을 하는 것은 쉽지 않다.
따라서 이러한 요구 사항을 충족하기 위해 중간에 Adapter를 두는 어댑터 패턴을 사용하는 것이다.
만약 핸들러 어댑터를 사용하면, 핸들러에서 결괏값을 어떻게 반환하든 이를 처리해 DispatcherServlet에게 ModelAndView객체로 통일하여 응답을 전달해 줄 수 있다.
이처럼 핸들러 어댑터를 사용하면 개발자는 좀 더 비즈니스 로직 구현에 집중할 수 있기 때문에 사용하는 것이다.
다행히, Spring은 이미 필요한 핸들러 매핑과 핸들러 어댑터를 대부분 구현해두었기 때문에 개발자가 직접 핸들러 매핑과 핸들러 어댑터를 구현하는 일은 거의 없다.
참고