부트 개념과 활용-04.내장 웹 서버 이해
내장 웹 서버 이해
스프링 부트는 서버가 아닙니다. 하지만..
- 톰캣 객체 생성
- 포트 설정
- 톰캣에 컨텍스트 추가
- 서블릿 만들기
- 톰캣에 서블릿 추가
- 컨텍스트에 서블릿 맵핑
- 톰캣 실행 및 대기
- ServletWebServerFactoryAutoConfiguration (서블릿 웹 서버 생성)
이 모든 과정을 보다 상세히 또 유연하고 설정하고 실행해주는게 바로 스프링 부트의 자동 설정입니다.
또한 자동 설정되어있는 되는 서버를 커스터마이징 할 수도 있습니다.
- TomcatServletWebServerFactoryCustomizer (서버 커스터마이징)
- DispatcherServletAutoConfiguration
- 서블릿 만들고 등록 등..
자동 설정이 되어있지 않다면?…
public class Application {
public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
Context context = tomcat.addContext("/", "/");
HttpServlet servlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("<html><head><title>");
writer.println("hey, jaeuk tomcat");
writer.println("</title></head>");
writer.println("<body><h1>hi jaeuk!</h1></body");
writer.println("</html>");
writer.println("<html><head><title>");
}
};
String serveletName = "helloServelet";
tomcat.addServlet("/", serveletName, servlet);
context.addServletMapping("/hello", serveletName);
// /hello 요청이 오면 serveletName(helloServelet) 위에서 생성한 서블릿을 보여주는 것
tomcat.start();
tomcat.getServer().await();
}
}
실행 결과
사실 이런 것들이 다 자동 설정이 되는 것입니다..
이전 포스트인 자동설정과 관련이 있는데,
스프링 부트 어플리케이션을 실행하면 톰캣이 만들어지고 서블릿이 추가되고 웹MVC 설정이 되고 띄워지는 것.
이전 포스트에서 살펴본
spring-boot-autoconfigration - META-INF - spring.factories 안을 보면
...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
...
이 존재합니다. (자동 설정)
@EnableAutoConfiguration가 자동 설정하는 리스트들 중에 ServletWebServerFactoryAutoConfiguration 이 안을 보면
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
...
Import 중에 ServletWebServerFactoryConfiguration.EmbeddedTomcat.class 가 있습니다.
(EmbeddedTomcat)그 안을 한번 보면..
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
이 안의 TomcatServletWebServerFactory를 보면
커넥터, 컨텍스트 설정, 클래스 로더 등등.. 설정들을 다 해주고 있습니다.
마찬가지로 서블릿도 DispatcherServletAutoConfiguration 에서 자동 설정을 해 주고 있습니다.
spring-boot-autoconfigration - META-INF - spring.factories 안을 보면
...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
...
public class DispatcherServletAutoConfiguration {
...
protected static class DispatcherServletConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(
this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(
this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(
this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
return dispatcherServlet;
}
...
DispatcherServletAutoConfiguration 클래스 안에서 디스패처 서블릿(DispatcherServlet)이 만들어 집니다.
(httpServlet을 상속하여 만든 스프링의 MVC의 핵심 클래스)
이 클래스 안에서 디스패서 서블릿을 만들고 (DispatcherServletConfiguration class)
서블릿 컨테이너에 등록하는 일들이 이루어집니다.(DispatcherServletRegistrationConfiguration class)
디스패처 서블릿을 만드는 것과 서블릿 컨테이너에 등록하는 두 부분이 왜 나누어져 있냐면(이 둘이 왜 떨여져 있냐?)
서블릿 컨테이너는 다 달라질수 있는데, (톰캣 등…) pom.xml 설정에 따라 다 달라지는데
서블릿은 변하지 않습니다.
그래서 둘이 분리가 되었습니다.
디스패서 서블릿은 내가 어떠한 서블릿 컨테이너를 쓰든 상관없이 얘를 만든 다음에
지금 있는 서블릿 컨테이너에 등록하는 과정이 이 안에서 벌어집니다.
예시 코드 및 더 자세한 설명은 다음 포스트에서 이어서 정리하겠습니다.