Spring Web MVC란 Spring Framework와 Servlet API를 기반으로 하는 웹 애플리케이션 프레임워크로, 주로 Spring MVC라고 줄여서 부른다.
이 Spring MVC는 이름에서 유추할 수 있듯이, 웹 요청을 Model-View-Controller로 역할을 분리해 처리하는 MVC 패턴을 사용한다는 특징이 있고 (그 중에서도 Controller 역할을 Servlet이 수행하고 결과를 JSP를 통해 리턴하는 MVC2 패턴을 사용)
데이터 바인딩 및 검증 기능을 제공하며, Interceptor를 제공해 요청을 처리하기 전 후로 보안 / 로깅과 같은 작업을 수행할 수 있다는 특징이 있다.
깊게 학습하기 위해서는 러닝 커브가 높다.
초기 환경 세팅과 설정이 복잡하다.
-> XML을 통해 Spring Bean 등록과 의존관계를 설정이 필요하다.
-> 단, Spring Boot를 사용하는 경우 간소화 및 자동화 해주기 때문에 해당사항 X
의존성 관리가 어렵다.
-> 스프링 프레임워크의 많은 라이브러리와 의존성을 사용하기 때문에, 라이브러리 버전 간 충돌이 발생할 수 있다.
-> 단, Spring Boot를 사용하는 경우 간소화 및 자동화 해주기 때문에 해당사항 X
위의 이미지는 스프링 MVC의 내부 구조로 실제로는 더욱 복잡하다.
Spring 웹 애플리케이션의 핵심 구성 요소 중에 하나로 FrontController 패턴으로 구현되어 있는 Servlet 객체다.
이 DispatcherServlet은 사용자의 요청을 처리하기 위해 매우 많은 역할을 한다.
- 클라이언트의 HTTP 요청 수신
- Handler Mapping 조회
- Handler Adapter 조회 및 Handler 실행
- Handler 메서드 실행 결과 클라이언트로 응답
HandlerMapping은 Spring MVC에서 클라이언트의 요청을 어떤 Handler가 처리할 지 결정하는 역할을 하는 인터페이스이다.
Handler 등록 방식에 따라 다양한 HandlerMapping 구현체가 존재하고, 각 구현체마다 특정 전략을 통해 매핑된 Handler를 조회한다.
예를 들어, RequestMapingHandlerMaping 클래스는 스프링 빈으로 등록된 컨트롤러를 조회해서 @RequestMapping의 URL과 요청 URL이 매칭되는지 확인한다.
HandlerMapping 인터페이스가 Handler를 조회하는 순서는 다음과 같다.
1. HandlerMapping 구현체 조회
- DispatcherServlet는 HandlerMapping 우선순위 순으로 순회하며 구현체를 가져온다.
2. Handler 조회
- 구현체의 getHandler 메서드를 통해 클라이언트의 요청을 처리할 Handler를 조회한다.
3. Handler 정보 리턴
- 만약 매핑되는 Handler가 존재한다면, Handler 인스턴스와 그 외의 추가 정보가 담긴 HandlerExecutionChain 객체를 반환한다.
HandlerAdapter는 Handler 메소드 호출을 위한 준비과정부터 실제 메소드 호출 및 메소드 응답값 처리를 수행하는 인터페이스이다.
HandlerMapping 인터페이스와 동일하게 Handler 등록 방법에 따른 다양한 HandlerAdapter 구현 클래스가 존재한다.
DispatcherServlet은 우선순위 순으로 HandlerAdapter 구현체를 순회하며 support 메소드를 호출해서 Handler를 지원하는 HandlerAdapter 구현체를 찾고, 찾은 HandlerAdapter 구현체의 handle 메소드를 호출해서 Handler 메서드를 실행한다.
HandlerAdapter의 handle 메소드의 내부 동작은 다음과 같다.
(1) HandlerMethod 추출
- HandlerAdapter는 Handler에 대한 객체로 HandlerMethod를 사용한다.
- HandlerExecutionChain 객체에서 Handler 인스턴스와 Handler 메소드의 어노테이션 / 매개변수 등의 정보를 추출해서HandlerMethod 객체에 담는다.
(2) Argument Resolver 호출
- HandlerMethod 객체로 부터 매개변수들을 해석하고 필요한 값을 추출하는 역할을 하는 인터페이스이다.
예시로, @RequestParam, @PathVariable 등의 어노테이션에 따라서 Handler메서드 호출에 필요한 값을 추출해낸다
(3) HandlerMethod 실행
- Argument Resolver를 통해 받은 매개변수 값과 함께 실제 Handler 메소드를 실행한다.
(4) ReturnValue Handler 실행
- Handler 메서드 실행 결과를 처리하는 인터페이스로, Handler 메서드의 유형에 따라 반환하는 값의 적절한 처리를 진행한다.
- 예시로, @ResponseBody 어노테이션이 붙은 메서드의 경우 ReturnValue Handler는 반환된 값을 JSON / XML 형태로 변환하는 처리가 이루어진다.
(5) 결과 반환
- 결과를 DispatcherServlet에 반환한다.
클라이언트의 요청을 실질적으로 처리하는 메서드로, 흔히 컨트롤러가 이 Handler에 해당된다.
Spring MVC 에서는 아래와 같이 Handler를 여러가지 방법을 통해 등록할 수가 있는데, 그 중 어노테이션 기반으로 Handler를 등록하는 것을 주로 사용한다.
@Controller 또는 @RestController 어노테이션으로 스프링 컨테이너에 등록하고, @RequestMapping 과 같은 어노테이션으로 URL을 매핑한다.
@Controller
public class MyController {
@RequestMapping("/hello")
public String hello() {
return "helloPage"; // 뷰의 논리적인 이름
}
}
Handler 인터페이스를 직접 구현하는 방식으로, 클래스명이 요청 URL로 매핑된다. (/myHandler)
public class MyHandler implements Handler {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 요청 처리 로직
return new ModelAndView("helloPage"); // 뷰의 논리적인 이름
}
}
Controller 인터페이스를 직접 구현하는 방식으로, 클래스명이 요청 URL로 매핑된다 (/myController)
public class MyController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 요청 처리 로직
return new ModelAndView("helloPage"); // 뷰의 논리적인 이름
}
}
Handler 메서드 결과 값인 View 이름을 설정된 prefix와 suffix를 기반으로 실제 뷰 객체를 찾아 반환하는 역할을 하는 인터페이스이다.
이 ViewResolver는 항상 호출되는 것은 아니고, @RestController와 같이 View를 사용하지 않는 메서드의 경우 생략된다.
클라이언트(웹 브라우저, 모바일 앱 등)에서 HTTP 요청이 생성된다.
요청은 URI(Uniform Resource Identifier)와 함께 HTTP 메서드(GET, POST, PUT, DELETE 등)와 헤더, 본문 등의 정보를 포함한다.