필터는 서블릿이 제공하는 기능이다.
주로 공통 관심사 기능을 적용할 때 사용한다. (모든 고객의 요청을 기록하는 일, 로그인 권한을 확인하는 일)
서블릿은 Http헤더나 URL을 제공하는 HttpServletRequest를 사용할 수 있다.
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
필터 제한
Http -> WAS -> 필터 -> 서블릿 -> 컨트롤러
Http -> WAS -> 필터 (적절하지 않은 요청의 경우 서블릿 호출 x)
필터 체인
Http 요청 -> WAS -> 필터1 -> 필터2 -> 필터3 -> 서블릿 -> 컨트롤러
public interface Filter {
public default void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public default void destroy() {}
}
init() : 필터 초기화 메서드, 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고 관리함
doFilter() : 요청마다 로직이 호출됨, 필터의 로직을 구현
destroy() : 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출됨
@Override
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("log filter doFilter");
HttpServletRequest request = (HttpServletRequest) req;
String uri = request.getRequestURI();
String uuid = UUID.randomUUID().toString();
try{
log.info("REQUEST [{}][{}]",uuid,uri);
chain.doFilter(req, response);
}catch (Exception e){
throw e;
}finally {
log.info("RESPONSE [{}][{}]",uuid,uri);
}
}
요청이 들어오면 REQUEST URI 가 찍히고, 다음줄 doFilter로 이동해 다음 필터 또는 서블릿 -> 컨트롤러로 전달되고 다시 돌아오고 Fially문의 RESPONSE가 찍히게 된다.
스프링이 실행되면서 서블릿 컨테이너를 띄우기 떄문에 FilterRegistrationBean
을 빈으로 등록하면 필터가 등록된다.
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean logFilter() {
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new LogFilter());
filterFilterRegistrationBean.setOrder(1);
filterFilterRegistrationBean.addUrlPatterns("/*");
return filterFilterRegistrationBean;
}
}
필터는 인터셉터와 다르게 req,res 를 바꿔치기 한 뒤에 chain.doFilter()를 수행할 수 있다.