Spring 16. 서블릿 & 서블릿 컨테이너 & spring MVC
1. 서블릿, 서블릿 컨테이너, Dispatch Servlet
서블릿
- javax.servlet.Servlet 인터페이스의 구현체. 해당 인터페이스를 구현한 다음 web.xml 에 해당 구현체를 서블릿으로 등록하면, 서블릿 컨테이너가 이를 바탕으로 서블릿 객체를 생성하여 사용한다.
- 서블릿 컨테이너는 서블릿 객체 각각을 한개씩 생성한다.
서블릿 컨테이너
- 아파치톰캣이 서블릿 컨테이너에 해당된다.
서블릿 컨테이너의 역할
- 웹 애플리케이션 서버 프로그램의 main 함수가 여기에 있을 것이다.
- 서버 소켓을 생성하고 요청을 기다리다가, 클라이언트의 요청이 들어오면 새로운 thread 를 만든다.
- 서블릿 객체 생성 등, 서블릿의 라이프사이클을 관리한다.
Dispatcher Servlet
- spring-webmvc에서 제공하는 서블릿(=javax.servlet.Servlet 인터페이스의 구현체)
2. 스프링 MVC 프레임워크를 사용한 WAS 동작방식
1. 요청을 받은 서블릿 컨테이너는 해당 요청에 맞는 서블릿을 찾아서 서블릿의 service 메서드를 호출한다.
스프링 MVC 를 사용한 경우 Dispatcher Servlet 의 service 메서드를 호출할 것이다.
참고 : Servlet 인터페이스
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
스프링 MVC 프레임워크를 사용한 웹 프로젝트의 산출물로 Gradle__sprringmvc_war 라는 war 파일이 나왔다고 해보자. 이것을 톰캣의 webapps 폴더 밑에 둔 뒤 톰캣 서버를 실행하면 톰캣 서버가 war 압축을 풀어서 사용한다고 한다.
(톰캣은 war파일이 webapps폴더에 있으면 자동으로 알아서 압축을 풀어 웹어플리케이션을 사용할 수 있게 한다고 함)
나는 이 작업을 직접 하지는 않았지만, 인텔리J가 대신 해줬다고 생각하면 타당한 듯 하다. 실제로 인텔리J에서 프로젝트를 실행한 뒤 톰캣의 폴더 구조를 보니 다음과 같았다.
프로젝트를 처음 실행했을 때 url이 localhost:8080/Gradle__springmvc_war/xxx가 되어서 당황했는데, war 파일 이름이 Gradle__springmvc_war 로 되어서 그런 것으로 보인다.
즉 나의 경우,
/Gradle__springmvc_war 로 시작하는 요청이 왔을 때 서블릿 컨테이너가 Dispatcher Servlet 인스턴스의 service 메서드를 호출한 것이다.
이제부터는 DispatcherServlet#service() 가 실행되는 과정이다.
2. Dispatcher Servlet은 HandlerMapping 이라는 객체에게 컨트롤러 검색을 요청한다.
정확히 말하면 HandlerMapping 은 컨트롤러를 검색하는 것이 아니라 Handler를 검색하는 것이고, 컨트롤러는 Handler 중 하나라고 할 수 있다.
스프링MVC의 HandlerMapping 에는 다음 네가지 종류가 있다.
- BeanNameHandlerMapping : Bean 이름과 URL 을 매핑시켜준다.
- ControllerClassNameHandlerMapping
- SimpleHandlerMapping
- RequestMappingHandlerMapping
이 중에서 @Controller 어노테이션이 붙은 객체를 Handler 로 사용하는 방식은 RequestMappingHandlerMapping
이다. 만약 이 방식을 사용할거라면 RequestMappingHandlerMapping을 설정파일에서 Bean으로 등록해줘야 한다.
그런데 설정파일에 @EnableWebMvc 어노테이션을 사용하면 이 코드를 작성하지 않아도 된다.
@EnableWebMvc 어노테이션을 사용하면 매우 많은 스프링 빈을 추가해준다. 이 중에는
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 도 있다.
3. DispatcherServlet 은 HandlerMapping이 찾아준 컨트롤러 객체를 처리할 수 있는 HandlerAdapter bean에게 요청 처리를 위임한다.
HandlerAdapter는 컨트롤러의 알맞은 메서드를 호출해서 요청을 처리하고, 그 결과를 ModelAndView 객체로서 DispatcherServlet에 리턴한다.
근데 Rest Controller 도 결국은 ModelAndView 객체로 리턴하게 되는걸가..? 궁금
4. DispatcherServlet은 ModelAndView의 정보를 ViewResolver bean객체에게 넘기면서 View 객체를 요청한다.
만약 웹 프로젝트가 아래와 같은 설정파일을 사용했다고 하자.
package config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@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");
}
}
위 설정은 org.springframework.web.servlet.view.InternalResourceViewResolver 클래스를 이용해서 다음 설정과 같은 빈을 등록한다.
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/view/");
vr.setSuffix(".jsp");
return vr;
}
이 ViewResolver (InternalResourceViewResolver) 는
뷰 이름이 "hello" 라면 "/WEB-INF/view/hello.jsp" 경로를 뷰 코드로 사용하는 View (InternalResourceView) 객체를 리턴한다.
5. DispatcherServlet은 ViewResolver로부터 얻은 View 객체에게 응답 생성을 요청하고, 그 리턴값으로 브라우저에게 응답한다.
출처
초보 웹 개발자를 위한 스프링 5 프로그래밍 입문 chapter 10
서블릿 guruble.com/about-servlet/
Servlet Container 역할 workatit.tistory.com/19
Servlet & Spring Web MVC www.youtube.com/watch?v=2pBsXI01J6M
Tomcan & .war 파일 withcoding.com/38
서블릿 이름 gmlwjd9405.github.io/2018/10/29/web-application-structure.html