ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] Spring MVC - 필터, 인터셉터
    Study/Spring 2025. 4. 19. 21:26

    들어가기 전,

    Q. 필터와 인터셉터는 언제 사용하면 좋을까?

    • 공통 관심사는 스프링의 AOP로도 해결할 수 있지만, 웹과 관련된 공통 관심사는 서블릿 필터나 스프링 인터셉터를 사용하는 것이 좋음
    • 웹과 관련된 공통 관심사를 처리할 때는 HTTP 헤더나 URL 정보들이 필요한데, 서블릿 필터나 스프링 인터셉터는 HttpServletRequest를 제공

     

    Q. 둘 중 어떤 것을 사용할까?

    • 인터셉터는 스프링 MVC 구조에 특화된 필터 기능을 제공한다고 이해하면 됨
    • 스프링 MVC를 사용하고, 특별히 필터를 꼭 사용해야 하는 상황이 아니라면 인터셉터를 사용하는 것이 더 편리함

     

    서블릿 필터

    필터 흐름

    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
    • 필터를 적용하면 필터가 호출된 후에 서블릿이 호출
    • 필터는 특정 URL 패턴에 적용할 수 있음 (/* 이라고 하면 모든 요청에 필터가 적용됨)
    • 스프링을 사용하는 경우 여기서 말하는 서블릿은 스프링의 DispatcherServlet을 의미

     

    필터 제한

    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러 // 필터 통과 ex) 로그인 사용자
    HTTP 요청 -> WAS -> 필터 // 필터 미통과, 적절하지 않은 요청이라 판단하면 서블릿 호출 X ex) 비 로그인 사용자
    • 필터에 적절하지 않은 요청이라고 판단하면 서블릿을 호출하지 않고 끝냄

     

    필터 체인

    HTTP 요청 -> WAS -> 필터1 -> 필터2 -> 필터3 -> 서블릿 -> 컨트롤러
    • 필터는 체인으로 구성되어 여러 필터를 추가할 수 있음

     

    필터 인터페이스

    package jakarta.servlet;
    
    public interface Filter {
        default void init(FilterConfig filterConfig) throws ServletException {
        }
    
        void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
    
        default void destroy() {
        }
    }
    • 필터 인터페이스를 구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고 관리
    • 주요 메서드
      • init() : 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출
      • doFilter() : 요청이 올 때마다 해당 메서드가 호출됨. 필터의 로직을 구현하면 됨
      • destroy() : 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출

     

    스프링 인터셉터

    • 서블릿 필터가 서블릿이 제공하는 기능이라면, 스프링 인터셉터는 스프링 MVC가 제공하는 기술임
    • 둘다 웹과 관련된 공통 관심사항을 처리하지만, 적용되는 순서와 범위, 그리고 사용방법이 다름

     

    스프링 인터셉터 흐름

    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
    • DispatcherServlet과 컨트롤러 사이에서 컨트롤러 호출 직전에 호출
      • 스프링 인터셉터는 스프링 MVC가 제공하는 기능이기 때문에 DispatcherServlet 이후에 등장함
    • 스프링 인터셉터에도 URL 패턴을 적용할 수 있는데, 서블릿의 URL 패턴과는 다르고, 매우 정밀하게 설정할 수 있음

     

    스프링 인터셉터 제한

    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 // 스프링 인터셉터 통과
    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 // 적절하지 않은 요청이라 판단한 경우 컨트롤러 호출 X
    • 인터셉터에서 적절하지 않은 요청이라고 판단한 경우 컨트롤러를 호출하지 않음

     

    스프링 인터셉터 체인

    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터1 -> 인터셉터2 -> 컨트롤러
    • 스프링 인터셉터도 체인으로 구성되어 중간에 인터셉터를 추가할 수 있음

     

    스프링 인터셉터 인터페이스

    package org.springframework.web.servlet;
    
    public interface HandlerInterceptor {
        default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return true;
        }
    
        default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        }
    
        default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        }
    }
    • 스프링 인터셉터를 사용하려면 HandlerInterceptor 인터페이스를 구현하면 됨
    • 서블릿 필터의 경우 doFilter() 하나만 제공되지만, 인터셉터는 컨트롤러 호출 전(preHandle), 호출 후(postHandle), 요청 완료 이후(afterCompletion)와 같이 단계적으로 세분화되어 있음
    • 추가적으로 인터셉터는 어떤 컨트롤러(handler)가 호출되는지 호출 정보도 받을 수 있고, 어떤 ModelAndView가 반환되는지 응답 정보도 받을 수 있음

     

    스프링 인터셉터 호출 흐름

    정상 흐름

    • preHandle : 컨트롤러 호출 전(핸들러 어댑터 호출 전)에 호출
      • preHandle의 응답값이 true이면 다음으로 진행하고, false이면 더이상 진행하지 않음
      • false인 경우 나머지 인터셉트는 물론이고, 핸들러 어댑터도 호출되지 않음
    • postHandle : 컨트롤러 호출 후(핸들러 어댑터 호출 후)에 호출
    • afterCompletion : 뷰가 렌더링 된 이후에 호출

     

    스프링 인터셉터 예외 상황

    • preHandle : 핸들러 어댑터 호출 전에 호출됨
    • postHandle : 컨트롤러(핸들러)에서 예외가 발생하면 postHandle은 호출되지 않음
    • afterCompletion : 예외 상관없이 항상 호출됨
      • 예외가 발생하면 postHandle()은 호출되지 않으므로 예외와 무관하게 공통 처리를 하려면 afterCompletion()을 사용해야 함
      • 예외가 발생하면 afterCompletion()에 예외 정보를 포함해서 호출

     

    참고

    댓글

Designed by Tistory.