Servlet 3.0에 들어오면서 WAS에서 xml 내용이 제외되기 시작했다. 따라서 web.xml이 제거되고 자바 기반으로 동작할 수 있도록 구조적인 변경이 일어났다.
그럼 web.xml의 내용들은 어디로 없어졌을까?
web.xml의 흔적을 찾아서
ServletContainerInitializer
WAS는 처음 동작을 시작하면서 web.xml 파일을 로딩해서 애플리케이션(컨텍스트)를 초기화 한다. Servlet 3.0에서 부터는 XML없이 초기화를 진행하기 위해서 java를 실행해야할 필요가 생겼다. 그래서 등장한 친구가 ServletContainerInitializer가 그 역할을 한다. WAS는 classpath에 포함된 ServletContainerInitializer타입의 객체들을 로드해서 onStartup 메서드를 호출한다.
package jakarta.servlet;
import java.util.Set;
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
SpringServletContainerInitializer
따라서 ServletContainerInitializer를 구현한 클래스를 제공해주면 WAS와의 접점이 생기게 된다. 스프링에서 이 인터페이스를 구현해 놓은 클래스가 SpringServletContainerInitializer이다.
package org.springframework.web;
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = Collections.emptyList();
...
}
}
SpringServletContainerInitializer는 onStartup에서 역시 클래스 패스에서 WebApplicationInitializer 타입의 객체들을 모아서 처리하는데 이 파일의 내부에 web.xml과 관련된 내용들을 작성하게 된다.
WebApplicationInitializer
WebapplicationInitializer는 web.xml의 내용을 java로 처리하는 부분이라고 생각하면 쉽다.
package com.doding.hello;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import com.ssafy.hello.config.RootContextConfig;
import com.ssafy.hello.config.WebContextConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
public class CustomWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// root-context
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(RootContextConfig.class, WebContextConfig.class); // 웹과 무관한, 웹과 유관한
servletContext.addListener(new ContextLoaderListener(context));
// servlet-context
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
안녕! web.xml!
filter 등록하기
기본 filter 등록
일반 filter를 사용할 때는 단순히 @WebFilter를 이용하면 된다.
@WebFilter("/*")
public class CustomFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
System.out.println(req.getServletPath() + " requested" );
super.doFilter(req, res, chain);
System.out.println(req.getServletPath() + " responsed");
}
}
위의 예처럼 단순히 Servlet 프로그래밍에서 filter를 사용하던 것 처럼 filter를 만들면 손쉽게 filter를 사용할 수 있다.
filter에서 spring 빈 사용
하지만 위의 경우는 스프링과 무관하기 때문에 빈을 주입받는 등의 행위가 불가하다. 스프링과 연동해서 Filter를 사용하기 위해서는 DelegatingFilterProxy를 사용해야 한다.
https://goodteacher.tistory.com/590
[Spring@MVC] 스프링과 Filter
처음 스프링을 공부하면서 Spring@MVC는 DispatcherServlet부터 관여하고 Filter는 Servlet 이전에 동작하기 때문에 Filter는 Spring과는 무관한 기술이라고 뇌리 속에 박고 있었는데..스프링에서는 DelegatingFilte
goodteacher.tistory.com
@Component
//@WebFilter("/*")
public class CustomFilter extends HttpFilter {
@Autowired // 빈을 주입받고 싶다.
SimpleService ss;
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
System.out.println(req.getServletPath() + " requested" + ss.add(1, 2));
super.doFilter(req, res, chain);
System.out.println(req.getServletPath() + " responsed");
}
}
이 경우는 ServletContext에 DelegatingFilterProxy를 등록하고 이 녀석에게 CustomFilter를 연결하는 과정이 필요하다.
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// root-context
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(RootContextConfig.class, WebContextConfig.class); // 웹과 무관한, 웹과 유관한
servletContext.addListener(new ContextLoaderListener(context));
// 스프링과 연결된 Filter를 사용하려는 경우
FilterRegistration fr = servletContext.addFilter("customFilter", DelegatingFilterProxy.class);
fr.addMappingForUrlPatterns(null, false, "/*");
...
}