
Spring MVC의 구조를 깊이 있게 알기위해서는 기존의 MVC패턴의 전체 구조를 알고 이해하는 것이 도움이 될 것이다.
Spring MVC의 범위는 매우크고 기능 또한 매우 많기때문에 기본 베이스 없이 Spring MVC를 이해하려하면 매우 어려울 것이다.
MVC패턴과 변천사 - 핸들러와 핸들러어댑터 패턴 적용
이전 포스팅에서는 Model개념을 적용하여 request.serAttribute로 수행하던 파라미터 값을 가져오는 것을 Model을 통해 해결함으로 Servlet에 종속성을 제거하였다. 또 뷰 리졸버를 사용해서 각 컨트롤러
lee-dev-log.tistory.com
Dispatcher Servlet
Spring MVC에서도 프론트 컨트롤러 패턴이 사용되어 프론트 컨트롤러에서 뷰 리졸버 기능, Model을 담아 View로 넘겼던 기능 모두 DispatcherServlet에서 처리한다. 즉, 프론트 컨트롤러와 디스패쳐 서블릿은 이름만 다를 뿐 같은 역할을 수행한다.
아래 코드는 Spring Framework에 구현되어있는 DispathcherServlet클래스의 구현코드이다.

모든 코드들이 어떤 의미인지 자세히는 알 수 없지만 이 전 포스팅에서 다뤘던 handlerMapping, handlerAdapter, viewResolver등 이 전에 프론트 컨트롤러에서 구현해봤던 기능들이 DispatcherServlet과 관련이 있음을 알 수 있고 이 말은 곧 FrontController의 기능을 DispatcherServlet에서 동일하게 구현되어있음을 증명한다.
또한 이전에 FrontControllerServlet에서 HttpServlet을 상속하는 것을 아래 코드에서 확인할 수 있는데

인텔리제이에서 제공하는 클래스 다이어그램보기 기능을 통해 DispatcherServlet도 마찬가지로 HttpServlet을 상속함을 확인할 수 있다

DispatcherServlet클래스에는 doDispatch()라는 메서드가 있는데 이 메서드는 HttpServlet에서 사용했던 service()메서드와 동일한 개념의 메서드이다.
DispatcherServlet의 핵심 메서드인 doDispatch메서드를 알아보자.
이 전 포스팅에서 다뤘던 FrontController와 DispatcherServlet을 비교하며 설명해 볼텐데,
기존 DispatcherServlet클래스를 캡쳐한 코드에는 이미지에 캡션을 추가하도록 하겠다.
Dispatcher handler조회 및 매핑


Spring MVC 프레임워크에서도 getHandler라는 메서드를 통해서 핸들러를 조회하고 매핑하는데
List컬렉션인 handlerMappings변수를 순회하면서 핸들러 매핑정보를 조회하고 없을 경우에는 예외처리 시킨다는 것을 알 수 있다.
우리는 이 코드를 이전 포스팅에서는 아래와 같이 구현했었다.


Dispatcher HandlerAdapter 조회
HandlerAdapter또한 마찬가지로 handlerAdapters라는 List컬렉션을 순회하며 파라미터로 받은 handler에 맞는 어댑터를 지원하는지를 supports()메서드를 통해 확인하고 만약 지원하지 않는다면 ServletException예외처리 한다는 것을 확인할 수 있다.

우리는 위 코드를 이 전 포스팅에서 아래와 같이 구현해보았었다.

Handler 실행
매핑된 핸들러를 handle메서드를 통해 실행하고 ModelAndView타입으로 반환 받는다.

우리는 아래와 같이 구현했었다.

View 리졸버 처리 및 렌더링

우리는 위 코드를 아래와 같이 구현했었다.

지금까지 Dispatcher클래스와 우리가 구현했던 클래스를 비교해서 살펴보면 매우 유사하다는 것을 알 수 있으며, 전체적인 구조의 흐름이 같음을 확인할 수 있었다.
핸들러 매핑과 핸들러 어댑터
이제 Spring MVC프레임워크에서는 핸들러 매핑과 핸들러 어댑터가 어떻게 사용되는지 알아보자
아래 코드는 현재는 사용되지 않는 아주 오래된 Controller인터페이스를 예시로 구현한 코드이다.
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("OldController.handleRequest");
return new ModelAndView("new-form");
}
}
@Component는 Spring 컨테이너에 "/springmvc/old-conroller"라는 이름을 갖도록 스프링 빈을 등록한다.
이 때 "/springmvc/old-conroller"이 이름은 url을 매핑할 때 사용된다.
이 때 @Component 즉, 핸들러 매핑과 핸들러 어댑터는 이미 스프링MVC에 모두 구현되어있기 때문에 개발자가 직접 핸들러 매핑이나 핸들러 어댑터를 구현할 필요 없이 사용하기만 하면 된다.
Spring Boot가 지원하는 핸들러 매핑과 핸들러 어댑터
핸들러 매핑
1. RequestMappingHandlerMapping
- @RequestMapping어노테이션이 붙은 컨트롤러 메서드를 처리
- Spring MVC의 핵심적인 핸들러 매핑으로 대부분의 웹 애플리케이션에서 이를 통해 요청을 처리
2. SpimpleURlHandlerMapping
- URL패턴에 따라 핸들러를 직접 매핑할 때 사용
- 주로 정적 리소스나 특정 뷰 컨트롤러에 사용
- 예를 들어 웹 애플리케이션의 홈페이지나 특정 정적 리소스에 대한 간단한 매핑에 사용될 수 있다.
3. BeanNameUrlHandlerMapping
- 빈의 이름을 URL로 사용하여 매핑
- 사용 빈도는 낮지만 특정 경우에 유용할 수 있다.
- 위에서 살펴본 "/springmvc/old-conroller"이 예시이다
실무에서 핸들러 매핑으로는 @RequestMapping의 어노테이션 기반이 99%사용 된다고 한다.
핸들러 어댑터
1. RequestMappingHandlerAdapter
- ReqeustMappingHandlerMapping에 의해 선택된 핸들러 메서드를 실행
- @RequestMapping 어노테이션을 사용하는 컨트롤러에 대한 주요 핸들러 어댑터
2. HttpRequestHandlerAdapter
- HttpRequestHandler인터페이스를 구현한 핸들러를 지원
- 주로 정적 리소스 처리 등에 사용
3. SimpleControllerHandlerAdapter
- Controller인터페이스를 구현한 핸들러를 지원
- Spring MVC에서 @Controller어노테이션을 사용하지않고 직접 Controller인터페이스를 구현할 때 사용
- 위에서 OldCOntroller에 대한 핸들러 어댑터이다.
뷰 리졸버
Spring MVC에서 뷰 리졸버는 어떻게 사용되는지 알아보자
먼저 아래 예시에서 new-form이라는 논리 뷰 이름을 반환 받았으며 new-form이라는 뷰 이름으로 viewResolver를 호출하게 된다
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("OldController.handleRequest");
return new ModelAndView("new-form");
}
}
Spring Boot가 자동으로 등록하는 뷰 리졸버
1. ContentNegotiatingViewResolver
- 다른 뷰 리졸버들을 내부적으로 관리하고 요청에 가장 적합한 뷰를 결정하기위해 HTTP Accept헤더 또는 요청파일 확장자를 고려하여 JSON, XML, HTML등 다양한 형태의 응답을 동적으로 제공
2. ThymeleafViewResolver
- Thymeleaf템플릿 엔진을 사용하는 애플리케이션의 경우, 스프링 부트는 자동으로 ThymeleafViewResolver를 구성
3. InternalResourceViewResolver
- JSP를 사용할 때 주로 사용되며 JSP파일 경로를 해석하여 뷰를 제공.
현재 상황에서는 new-form이라는 빈이름으로 등록된 뷰가 없기 때문에 InternalResourceViewResolver가 호출되어 JSP의 같은 경우 InternalResourceView에서 내부적으로 forward()를 통해서 렌더링이 된다.
이 때 application.properties파일을 아래와 같이 JSP파일의 경로로 설정해주어야 스프링에서 자동으로 매핑하여 JSP를 실행한다.
// application.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
아래와 같이 우리가 구현한 ViewResolver와 같은 역할을 한다.
private MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
위 정리한 내용들은 모두 인프런에서 김영한님의 강의를 듣고 학습한 내용을 스스로 정리한 것임을 밝힙니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1#
'Framework > Spring' 카테고리의 다른 글
Spring MVC - @RequestMapping (0) | 2024.04.16 |
---|---|
Spring MVC - 프레임워크 사용 전과 후 & @Controller (0) | 2024.04.15 |
스프링 컨테이너와 싱글톤 (0) | 2024.03.23 |
객체지향 설계를 위한 5가지 원칙 (SOLID) (0) | 2024.03.20 |
스프링이란? with 객체지향 (0) | 2024.03.20 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!