Servlet
요즘에는 자바 웹 애플리케이션을 만들 때 스프링 사용이 기본이 되기 때문에 서블릿을 등록하고 사용할 일이 거의 없다. DispatcherServlet 정도만 사용할 것이다
따라서 우리가 사용하는 서블릿은 DispatcherServlet이 유일하다고 생각할 수 있는데 그렇지 않다
Built In Servlets
톰캣 바이너리의 conf 폴더에는 web.xml이 있는데, 내용을 살펴보면 내장 서블릿 2개를 정의하고 있다
Default Servlet
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
주석에는 아래와 같이 적혀 있다
- 정적 자원을 제공하는, 모든 웹 애플리케이션을 위한 기본 서블릿
- 다른 서블릿에 매핑되지 않는 모든 요청을 처리한다 (/ 경로에 매핑되어 있음에 주목)
JSP Servlet
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
주석에는 아래와 같이 적혀 있다
- JSP 페이지를 지원하기 위해 톰캣에서 사용되는 메커니즘인, JSP 페이지 컴파일러 및 실행 서블릿
- 전통적으로 *.jsp URL 패턴에 매핑되어 있다
.jsp, .jspx 확장자 패턴 요청에 매핑된다
DispatcherServlet과 Default Servlet
외장 톰캣을 사용하는 경우가 아닌 스프링 부트를 사용하여 내장 톰캣을 사용하여 web.xml을 사용하지 않는 경우에는 그럼 어떻게 동작할까? 보통 그렇듯 DispatcherServlet만 등록하게 되면 나머지 서블릿들은 어떻게 되는 걸까?
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/default-servlet-handler.html
스프링 MVC는 DispatcherServlet을 /에 매핑하고 있다(톰캣 컨테이너의 기본 서블릿을 재정의)
결국 정적 자원 처리까지 담당하게 된다는 뜻이다
그런데 스프링에 등록된 빈을 출력해보면 defaultServletHandlerMapping이 있다. 그러면 Default Servlet을 쓰는 게 아닐까?
WebMvcConfigurationSupport.java
...
@Bean
@Nullable
public HandlerMapping defaultServletHandlerMapping() {
Assert.state(this.servletContext != null, "No ServletContext set");
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
configureDefaultServletHandling(configurer);
return configurer.buildHandlerMapping();
}
...
defaultServletHandlerMapping 빈은 여기서 등록된다. DefaultServletHandlerConfigurer 객체가 핸들러 매핑을 만들고 있다
DefaultServletHandlerConfigurer.java
...
@Nullable
protected SimpleUrlHandlerMapping buildHandlerMapping() {
if (this.handler == null) {
return null;
}
return new SimpleUrlHandlerMapping(Collections.singletonMap("/**", this.handler),
Ordered.LOWEST_PRECEDENCE);
}
...
여기서 핸들러를 /** URL에 매핑하고 가장 낮은 우선순위로 설정하고 있다. 하지만 실제로 애플리케이션을 실행하면 핸들러가 null이기 때문에 예상한대로 동작을 하지는 않는다
기본적으로 비활성화되어 있다. 이를 활성화하려면 아래와 같이 설정 클래스를 만들어 기본 설정을 변경해야 한다
WebConfiguration.java
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
그러면 아래의 코드가 실행되어 핸들러가 설정된다
DefaultServletHandlerConfigurer.java
...
public void enable() {
enable(null);
}
public void enable(@Nullable String defaultServletName) {
this.handler = new DefaultServletHttpRequestHandler();
if (defaultServletName != null) {
this.handler.setDefaultServletName(defaultServletName);
}
this.handler.setServletContext(this.servletContext);
}
...
DefaultServletHttpRequestHandler.java
...
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Assert.state(this.servletContext != null, "No ServletContext set");
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
if (rd == null) {
throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
this.defaultServletName + "'");
}
rd.forward(request, response);
}
...
자 이제 마지막으로 이 객체를 살펴보자. 이 핸들러는 기본적으로 "default"라는 이름으로 등록된 Default Servlet의 Wrapper인 RequestDispatcher를 통해 요청을 전달(Forward)한다
DispatcherServlet과 JSP Servlet
DispatcherServlet은 모든 요청을 받아 처리하는 Front Controller다
각 컨트롤러의 처리 결과에서 논리적인 뷰 이름을 얻고 실제 뷰 객체를 알기 위해 ViewResolver에게 처리를 위임한다
JSP를 사용하는 경우 InternalResourceViewResolver가 사용된다
InternalResourceViewResolver는 논리 뷰 이름으로 실제 JSP 파일 경로를 결정하고 JSP 파일 경로를 JSP Servlet에 전달한다
JSP Servlet은 JSP 파일을 HTML로 렌더링한다
DispatcherServlet이 HTML을 응답한다
결론
Default Servlet과 JSP Servlet은 자동으로 사용되어지지 않는다. 사용이 필요하면 설정하자
'Web Server > Apache Tomcat' 카테고리의 다른 글
| Tomcat > 로그 파일 내 한글 깨짐 해결 (0) | 2024.06.10 |
|---|---|
| Tomcat > 성능 튜닝 > 기본 (0) | 2023.12.01 |
| Tomcat > 성능 튜닝을 위한 사전 학습 (1) | 2023.11.29 |