상세 컨텐츠

본문 제목

[스프링 1] 10장. 스프링 MVC 프레임워크 동작 방식

22-23/22-23 Spring 1

by YUZ 유즈 2022. 11. 17. 10:02

본문

728x90

해당 포스트는 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문 [최범균 저] 책 내용을 참고하였습니다.


 

❗ 스프링 MVC 핵심 구성 요소

스프링 MVC의 핵심 구성 요소

  • <<spring bean>>: 스프링 빈으로 등록해야 하는 것
  • 회색 배경: 개발자가 직접 구현해야하는 요소

DispatcherServlet모든 연결을 담당한다.

웹 브라우저로부터 요청이 오면 DispatcherServlet은 그 요청을 처리하기 위해 HandlerMapping에게 요청하여 컨트롤러 객체를 검색한다

 

HandlerMapping은 클라이언트의 요청 경로를 이용해 이를 처리할 컨트롤러 빈 객체를 DispatcherServlet에게 다시 전달한다.

 

컨트롤러 객체를 전달 받았다고 바로 컨트롤러 객체의 메서드를 실행할 수 있지는 않다.

@Controller, Controller 인터페이스, HttpRequestHandler 인터페이스를 동일한 방식으로 처리하기위해 중간에 HandlerAdpater 빈이 존재한다.

DispatcherServlet은 HandlerAdapter 빈에 컨트롤러 요청 처리를 위임하고, 컨트롤러 처리 결과를 ModelAndView라는 객체로 변환해서 DispatcherServlet은 리턴 받는다.

 

요청 결과를 보여줄 빈을 찾기 위해 DispatcherServlet은 ViewResolver 빈 객체를 사용한다.

ModelAndView에는 컨트롤러가 리턴한 뷰 이름을 담고 있어서, ViewResolver가 이 뷰 이름에 해당하는 View 객체를 찾거나 생성해서 리턴할 수 있다.

 

DispatcherServlet은 ViewResolver가 리턴한 View 객체에게 응답 결과 생성을 요청한다.

JSP를 사용하는 경우, View 객체는 JSP를 실행함으로써 웹 브라우저에 전송할 응답 결과를 생성하고 모든 과정이 끝난다.


❗ DispatcherServlet과 스프링 컨테이너

9장의 web.xml 파일에서 DispatcherServlet의 contextConfiguration 초기화 파라미터를 이용해 스프링 설정 클래스 목록을 전달한 것을 볼 수 있다.

	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
        ...
		<init-param>
			<param-name>contextConfigLocation</param-name> <!--!-->
			<param-value>
				config.MvcConfig
				config.ControllerConfig
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

 

DispatcherServlet전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성한다.

HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver 등의 빈은 DispatcherServlet가 생성한 스프링  컨테이너에서 구하므로 이 설정 파일에 위 빈에 대한 정의가 포함되어 있어야 한다.


❗ @Controller를 위한 HandlerMapping과 HandlerAdapter

HandlerMapping과 HandlerAdapter 빈에 대한 정의는 DispatcherServlet에 전달 되는 설정 파일에 포함되어있어야 한다고 했다. 하지만 9장에서 예제에서는 @EnableWebMvc 애노테이션만 추가했다. 

 

@EnableWebMvc는 매우 다양한 스프링 빈 설정을 추가해준다.

그 중 @Controller 타입의 핸들러 객체를 처리하기 위한 아래 두 클래스도 포함되어있다.

  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdpater

RequestMappingHandlerMapping은 @Controller가 적용된 객체의 요청 매핑 애노테이션(@GetMapping) 값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾는다.

 

RequestMappingHandlerAdpater은 컨트롤러의 메서드를 알맞게 실행하고 그 결과를 ModelAndView 객체로 변환해서 DispatcherServlet에 리턴한다.

컨트롤러 메서드 결과 값이 String이면 해당 값을 뷰 이름으로 갖는 ModelAndView 객체를 생성해서 DispatcherServlet에 리턴한다. Model 객체에 보관된 값도 함께 전달한다.


❗ JSP를 위한 ViewResolver

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
    		//JSP를 위한 ViewResolver 설정
		registry.jsp("/WEB-INF/view/", ".jsp");
	}

}

첫번째 인자는 prefix, 두번째 인자는 suffix"prefix+뷰이름+suffix" 경로를 뷰 경로로 사용한다.

 

9장의 HelloController에서 아래와 같이 Model에 속성을 전달했다.

model.addAttribute("greeting", "안녕하세요, " + name);

이 경우 DispatcherServlet은 View 객체에 응답 생성을 요청할 때 greeting 키를 갖는 Map 객체View 객체에 전달한다.

View 객체에서는 Map 객체에 담긴 값을 이용해서 알맞은 응답 결과를 출력한다. 


디폴트 핸들러와 HandlerMapping의 우선순위

<servlet-mapping>
	<servlet-name>dispatcher</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

9장의 web.xml 설정에서 DispatcherServlet에 대한 매핑 경로를 '/'로 주었다.

.jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리하게 되는데, /index.html이나 /css/bootstrap.css 같은 요청도 처리하게 된다.

@EnableWebMvc 애노테이션이 등록하는 HandlerMapping은 @Controller 애노테이션을 적용한 빈 객체가 처리할 수 있는 요청 경로만 대응할 수 있다.(/hello)

 

 

/index.html이나 /css/bootstrap.css 같은 경로는 어떻게 처리할까?

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

}

DefaultServletHandlerConfigurer는 아래 두 빈 객체를 추가한다.

  • DefaultServletHttpRequestHandler
  • SimpleUrlHandlerMapping

SimpleUrlHandlerMapping을 이용해 모든 경로("/**")를 DefaultServletHttpRequestHandler를 이용해서 처리하도록 설정한다.

DefaultServletHttpRequestHandler는 클라이언트의 모든 요청을 WAS(웹 어플리케이션 서버)가 제공하는 디폴트 서블릿에 전달한다.

 

@EnableWebMvc가 등록하는 RequestMappingHandlerMapping의 적용 우선순위가 DefaultServletHandlerConfigurer의 enable() 메서드가 등록하는 SimpleUrlHandlerMapping보다 높다.

그렇기 때문에 웹 브라우저의 요청이 들어오면 DispatcherServlet은 다음 방식으로 요청을 처리한다.

  1. RequestMappingHandlerMapping으로 요청을 처리할 핸들러 검색
    • 존재하면 해당 컨트롤러로 요청 처리
  2. 존재하지 않으면 SimpleUrlHandlerMapping으로 요청 처리할 핸들러 검색
    • 모든 경로에 대해 DefaultServletHttpRequestHandler를 리턴
    • DispatcherServlet은 DefaultServletHttpRequestHandler에 처리 요청
    • DefaultServletHttpRequestHandler은 디폴트 서블릿에 처리 위임

 

DefaultServletHandlerConfigurer의 enable()메서드 외에 몇몇 설정도 SimpleUrlHandlerMapping을 등록하지만 enable()이 등록하는 때에 우선순위가 가장 낮다.

따라서 DefaultServletHandlerConfigurer의 enable()을 설정하면 별도 설정이 없는 모든 요청 경로를 디폴트 서블릿이 처리하게 된다.


Spring 1

EDITOR: OJO

728x90

관련글 더보기