[Spring] 스프링 MVC(19) - 서블릿 3 기반 설정
서블릿 3 기반 설정
서블릿 3 버전부터 web.xml 파일을 사용하는 대신 자바 코드를 이용해서 서블릿 / 필터를 등록할 수 있게 되었다. 방법은 WebApplicationInitializer 인터페이스를 상속받아 알맞게 구현해주면 된다. 다음은 그 예이다.
public class SpringServletConfig implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
XmlWebApplicationContext servletAppContext = new XmlWebApplicationContext();
servletAppContext.setConfigLocation("/WEB-INF/dispatcher.xml");
DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext);
ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher", dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addMapping("*.do");
}
}
WebApplicationInitializer 인터페이스를 상속받은 클래스는 onStartUp() 메서드에서 DispatcherServlet을 직접 생성해서 ServletContext에 등록해주면 된다. 위 코드는 다음과 같은 web.xml을 사용하는 것과 동일하다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="spring4-chap10" version="3.0">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
스프링은 WebApplicationInitializer 인터페이스를 상속받아 필요한 기능을 미리 구현한 추상 클래스를 제공하고 있다. 이들 추상 클래스는 다음과 같이 3개가 존재한다.

스프링 설정으로 XML을 사용한다면 다음과 같이 AbstractDispatcherServletInitializer 클래스를 상속받아 필요한 메서드만 재정의하면 된다.
public class SpringServletConfig2 extends AbstractDispatcherServletInitializer {
// abstract 메서드 재정의
@Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext servletAppContext = new XmlWebApplicationContext();
servletAppContext.setConfigLocation("/WEB-INF/dispatcher.xml");
return servletAppContext;
}
// 상위 클래스는 "dispatcher" 리턴
@Override
protected String getServletName() {
return "dispatcher2"; // 기본 값은 "dispatcher"
}
// abstract 메서드 재정의
@Override
protected String[] getServletMappings() {
return new String[]{"*.do"};
}
// 상위 클래스는 true 리턴
@Override
protected boolean isAsyncSupported() {
return super.isAsyncSupported();
}
// abstract 메서드 재정의
@Override
protected WebApplicationContext createRootApplicationContext() {
XmlWebApplicationContext rootAppContext = new XmlWebApplicationContext();
rootAppContext.setConfigLocation("/WEB-INF/root.xml");
return rootAppContext;
}
// 상위 클래스는 기본으로 null 리턴
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("utf-8");
Filter[] filters = new Filter[]{encodingFilter};
return filters;
}
}
위 코드에서 주요 메서드는 다음과 같다.
- createServletApplicationContext() : DispatcherServlet이 사용할 WebApplicationContext 객체를 생성한다.
- getServletName() : DispatcherServlet의 서블릿 이름을 리턴한다. (재정의하지 않을 경우 기본값은 "dispatcher")
- getServletMappings() : 생성할 DispatcherServlet이 매핑될 경로를 리턴한다.
- isAsyncSupported() : DispatcherServlet이 비동기를 지원하지 여부를 리턴한다. (재정의하지 않을 경우 기본 값은 true)
앞서 WebApplicationInitializer 인터페이스를 상속받은 경우와 달리 DispatcherServlet 객체를 직접 생성할 필요는 없다. DispatcherServlet 객체는 상위 클래스인 AbstractDispatcherServletInitializer에서 생성하며, 생성 과정에서 위에서 언급한 네 가지의 메서드를 이용해 DispatcherServlet을 설정한다. 나머지 2개의 메서드는 다음과 같다.
- createRootApplicationContext() : 루트 컨텍스트를 생성한다. 필요 없다면 null을 리턴하면 된다.
- getServletFilters() : DispatcherServlet에 적용할 서블릿 필터 객체를 리턴한다.
XML 설정이 아니라 @Configuration 기반 자바 설정을 사용하고 싶다면, 다음과 같이 AbstractAnnotationConfigDispatcherServletInitializer 클래스를 상속받아 좀 더 간결하게 설정할 수 있다.
public class SpringServletConfig3 extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
// 상위 클래스는 "dispatcher" 리턴
@Override
protected String getServletName() {
return "dispatcher3"; // 기본 값은 "dispatcher"
}
// abstract 메서드 재정의
@Override
protected String[] getServletMappings() {
return new String[]{"*.do"};
}
// 상위 클래스는 true 리턴
@Override
protected boolean isAsyncSupported() {
return super.isAsyncSupported();
}
// 상위 클래스는 기본으로 null 리턴
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("utf-8");
Filter[] filters = new Filter[]{encodingFilter};
return filters;
}
}
앞서 XmlWebApplicationContext 객체를 직접 생성했던 것과 달리 getRootConfigClasses() 메서드와 getServletConfigClasses() 메서드에서 사용할 클래스 목록을 리턴하는 것으로 끝난다. 실제 AnnotationConfigWebApplicationContext 객체를 생성하는 것은 상위 클래스인 AbstractAnnotationConfigDispatcherServletInitializer에서 이루어진다.
Reference
- 웹 개발자를 위한 Spring 4.0 프로그래밍 (최범균 저)