스프링 MVC 프레임 워크

HeeSeong·2021년 8월 3일
0
post-thumbnail

스프링 MVC 프레임 워크 동작


스프링 MVC 핵심 구성 요소



스프링 MVC의 핵심 구성 요소이다. 중앙의 DispatcherServlet은 모든 연결을 담당한다. 웹 브라우저로부터 요청이 들어오면 DispatcherServlet은 그 요청을 처리하기 위한 컨트롤러 객체를 검색한다. 이때 DispatcherServlet은 직접 컨트롤러를 검색하지 않고 HandlerMapping이라는 빈 객체에 컨트롤러 검색을 요청한다.

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

컨트롤러 객체를 DispatcherServlet이 전달받았다고 해서 바로 컨트롤러 객체의 메서드를 실행할 수 있는 것은 아니다. DispatcherServlet은 @Controller 애노테이션을 이용해서 구현한 컨트롤러 뿐만 아니라 스프링 2.5까지 주로 사용됐던 Controller 인터페이스를 구현한 컨트롤러, 특수 목적의 HttpRequestHandler 인터페이스를 구현한 클래스를 동일한 방식으로 실행할 수 있도록 만들어졌다. 이들을 동일한 방식으로 처리하기 위해 중간에 사용되는 것이 HandlerAdapter 빈이다.

DispatcherServlet은 HandlerMapping이 찾아준 컨트롤러 객체를 처리할 수 있는 HandlerAdapter 빈에게 요청 처리를 위임한다. HandlerAdapter는 컨트롤러의 알맞은 메서드를 호출해서 요청을 처리하고 그 결과를 DispatcherServlet에 리턴한다. 이때 HandlerAdapter는 컨트롤러의 처리 결과를 ModelAndView라는 객체로 변환해서 DispatcherServlet에 리턴한다.

HandlerAdapter로부터 컨트롤러의 요청 처리 결과를 ModelAndView로 받으면 DispatcherServlet은 결과를 보여줄 뷰를 찾기 위해 ViewResolver 빈 객체를 사용한다. ModelAndView는 컨트롤러가 리턴한 뷰 이름을 담고 있는데, ViewResolver는 이 뷰 이름에 해당하는 View 객체를 찾거나 생성해서 리턴한다.

DispatcherServlet은 ViewResolver가 리턴한 View 객체에게 응답 결과를 요청한다. JSP를 사용하는 경우 View 객체는 JSP를 실행함으로써 웹 브라우저에 전송할 응답 결과를 생성하게 된다.


DispatcherServlet과 스프링 컨테이너


	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<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>

web.xml 파일을 보면 DispatcherServlet의 contextConfiguration 초기화 파라미터를 이용해서 스프링 설정 클래스 목록을 전달했다. DispatcherServlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성하는데 HandlerMapping, HandlerAdapter, Controller, ViewResolver 등의 빈은 DispatcherServlet이 생성한 스프링 컨테이너에서 구한다. 따라서 DispatcherServlet이 사용하는 설정 파일에 이들 빈에 대한 정의가 포함되어 있어야 한다.



HandlerMapping & HandlerAdapter


@Configuration
@EnableWebMvc
public class MvcConfig {
}

@Controller 적용 객체는 DispatcherServlet 입장에서 보면 한 종류의 핸들러 객체이다. DispatcherServlet은 스프링 컨테이너에서 HandlerMapping과 HandlerAdapter 타입의 빈을 사용하므로 핸들러에 알맞은 각각의 빈이 스프링 설정에 등록되어 있어야 한다. 하지만 따로 빈으로 등록없이 @EnableWebMvc 애노테이션만 추가했다. 이것은 매우 다양한 스프링 빈 설정을 추가해준다. 이 태그가 빈으로 추가해주는 클래스 중에 @Controller 타입의 핸들러 객체를 처리하기 위한 RequestMappingHandlerMapping, RequestMappingHandlerAdapter 두개의 클래스가 포함되어 있다.

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

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


WebMvcConfigurer 인터페이스와 설정


@EnableWebMvc 애노테이션을 사용하면 @Controller 애노테이션을 붙인 컨트롤러를 위한 설정을 생성한다. 또한 @EnableWebMvc 애노테이션을 사용하면 WebMvcConfigurer 타입의 빈을 이용해서 MVC 설정을 추가로 생성한다.


@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

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

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
	}
}

설정 클래스는 WebMvcConfigurer 인터페이스를 상속하고 있다. @Configuration 애노테이션을 붙인 클래스 역시 컨테이너 빈으로 등록되므로 MvcConfig 클래스는 상속받았으므로 WebMvcConfigurer 타입의 빈이 된다.

@EnableWebMvc 애노테이션을 사용하면 WebMvcConfigurer 타입인 빈 객체의 메서드를 호출해서 MVC 설정을 추가한다. 스프링5 버전은 자바8 버전부터 지원하는 디폴트 메서드를 이용해서 WebMvcConfigurer 인터페이스의 메서드에 기본 구현을 제공하고 있다. 이 인터페이스를 상속한 설정 클래스는 재정의가 필요한 메서드만 구현하면 된다.


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


위의 web.xml 설정을 보면 DispatcherServlet에 대한 매핑 경로를 '/'로 주었다. 이 경우 .jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리한다. 즉 /index.html이나 /css/bootstrap.css와 같이 확장자가 .jsp가 아닌 모든 요청을 DispatcherServlet이 처리하게 된다.

그런데 @EnableWebMvc 애노테이션이 등록하는 HandlerMapping은 @Controller 애노테이션을 적용한 빈 객체가 처리할 수 있는 요청 경로만 대응할 수 있다. 따라서 /index.html이나 /css/bootstrap.css와 같은 요청을 처리할 수 있는 컨트롤러 객체를 찾지 못해 DispatcherServlet은 404 응답을 전송한다.


이와 같은 경로를 처리하기 위한 컨트롤러 객체를 직접 구현할 수도 있지만, WebMvcConfigurer의 configureDefaultServletHandling() 메서드를 사용하는 것이 편리하다.

위 설정에서 configureDefaultServletHandling 메서드의 DefaultServletHandlerConfigurer.enable() 메서드는 DefaultServletHttpRequestHandler, SimpleUrlHandlerMapping 두 빈 객체를 추가한다.

DefaultServletHttpRequestHandler는 클라이언트의 모든 요청을 WAS가 제공하는 디폴트 서블릿에 전달한다. 예로 /index.html에 대한 처리를 SimpleUrlHandlerMapping을 이용해서 모든 경로 /** 를 DefaultServletHttpRequestHandler를 이용해서 처리하도록 설정한다. DefaultServletHttpRequestHandler에 요청하면 이 요청을 다시 디폴트 서블릿에 전달해서 처리하도록 한다. 이 요청을 다시 디폴트 서블릿에 전달해서 처리하도록 한다.

@EnableWebMvc 애노테이션이 등록하는 RequestMappingHandlerMapping의 적용 우선순위가 DefaultServletHandlerConfigurer.enable() 메서드가 등록하는 SimpleUrlHandlerMapping의 우선순위 보다 높다. 따라서 DefaultServletHandlerConfigurer.enable()을 설정하면 별도 설정이 없는 모든 요청 경로를 디폴트 서블릿이 처리하게 된다.





profile
끊임없이 성장하고 싶은 개발자

0개의 댓글