출처 : https://programmer.group/spring-boot-configuration-servlet-filter-listener.html
스프링 부트 어플리케이션 내부에서 작동하는 내장 Servlet 3.0+ 컨테이너는 ServletContainerInitializer
와 WebApplicationInitializer
를 직접적으로 사용하지 않는다.
즉, 위의 2개 인터페이스를 구현하여 설정한 Filter
와 Listener
는 올바르지 못하다.
이는 타사 코드의 설계가 응용 프로그램을 손상시키지 못하게 하기 위해 의도적으로 고려된 설계이다.
임베디드 서블릿 컨테이너는 Servlet 3.0+
javax.servlet.ServletContainerInitializer
인터페이스 또는 Spring의org.springframework.web.WebApplicationInitializer
인터페이스를 직접 실행하지 않습니다.이것은 war 파일 내에서 실행되도록 설계된 타사 라이브러리가 Spring Boot 애플리케이션을 중단시킬 위험을 줄이기 위한 의도적인 설계 결정입니다.
spring boot 의 내장 서블릿 컨테이너는 위 문단의 인터페이스를 사용하지않기 때문에, 설정이 필요하다면
org.springframework.boot.context.embedded.ServletContextInitializer
인터페이스를 Bean
으로 등록해야한다.
해당 인터페이스는 함수형 인터페이스이며, #onStartUp() 함수를 구현하여 서블릿 컨텍스트에 접근 가능하다.
@Configuration
public class ServletConfig implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setSessionTimeout(30);// 분
servletContext.setInitParameter("resource","classpath:resources/application.yaml");
// 캐릭터 인코딩 필터
FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);
characterEncodingFilter.setInitParameter("encoding","UFT-8");
characterEncodingFilter.setInitParameter("forceEncoding","true");
characterEncodingFilter.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE,DispatcherType.ASYNC), // 디스패치타입
false, // false = 전 작동 , true = 후 작동
"/*"
);
characterEncodingFilter.setAsyncSupported(true);
servletContext.addListener(new ServletContextListener() {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("내장 톰캣 기동");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("내장 톰캣 종료");
}
});
}
}
ServletContextInitinalizer
를 RegistrationBean
이 구현하고 있으며, 하위의 3개의 클래스가 다시 RegistrationBean 을 상속하고 있다.
RegistrationBean 을 상속하고 있는 3개의 하위클래스는
런타임에 Servlet & Filter & Listener 를 자동 등록하는 역할
을하며, 해당 클래스는 전부 SpringBean 이여야만 합니다.
ServletRegistrationBean
: ServletContainer 가 초기화될 때, ServletContext 에 CustomServlet 을 등록시킨다.ServletListenerRegistrationBean
: ServletContainer 가 초기화될 때, ServletContext 에 CustomServletContextListener 를 등록시킨다.AbstractFilterRegistartionBean
: getFilter() 함수를 통해 Filter 생성과정을 하위클래스로 지연시키고 ServletContainer 가 초기화될 때, ServletContext 에 Filter 를 등록시킨다.@Bean
public ServletRegistrationBean servletRegistrationBean(ServletContext servletContext) {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
// 설정정보 기입
return servletRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean() {
ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
// 리스너추가
return servletListenerRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new CharacterEncodingFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setAsyncSupported(true);
Map<String ,String > initParam = new HashMap<>();
initParam.put("encoding","UTF-8");
initParam.put("forceEncoding","true");
filterRegistrationBean.setInitParameters(initParam);
return filterRegistrationBean;
}