-
[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()에 예외 정보를 포함해서 호출됨
참고
'Study > Spring' 카테고리의 다른 글
[Spring] 스프링 핵심 원리 - 동적 프록시 (0) 2025.04.20 [Spring] 스프링 핵심 원리 - ThreadLocal (1) 2025.04.19 [Spring] Spring MVC - 구조 이해 및 기본 기능 (0) 2025.04.19 [Spring] Spring MVC - 서블릿 (0) 2025.04.17 [Spring] 스프링 핵심 원리 - 빈 스코프 (0) 2025.04.17