영주머니의 개발주머니

필터(Filter) vs 인터셉터(Interceptor) 본문

Spring

필터(Filter) vs 인터셉터(Interceptor)

영주머니 2025. 5. 4. 20:25

디스패처 서블릿 (Dispatcher-Servlet)

  • HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러 (Front Controller)
  • 클라이언트로부터 어떤 요청이 오면 Tomcat과 같은 서블릿 컨테이너가 요청을 받게 되고, 이 모든 요청을 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 된다. 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야 하는 컨트롤러를 찾아서 작업을 위임하고 그 결과를 받아온다.

Filter vs Interceptor

Filter

  • 디스패처 서블릿에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.
  • Filter를 추가하기 위해서는 Filter 인터페이스의 init, doFilter, destory 메소드를 implements 해야 한다.
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
    • 필터 객체를 초기화하고 서비스에 추가하기 위한 메소드이다. 웹 컨테이너가 1회 init 메서드를 호출하여 필터 객체를 초기화하면 이후의 요청들은 doFilter를 통해 처리된다.
  • doFilter
    • doFilter 메소드는 url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메소드이다.
  • destory
    • 필터 객체를 서비스에서 제거하고 사용하는 자원을 반환하기 위한 메소드이다. 웹 컨테이너에 의해 1번 호출되며 이후에는 이제 doFilter에 의해 처리되지 않는다.

Interceptor

  • 디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.
  • 디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다. 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.
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 {
    }
}
  • preHandle
    • preHandle 메소드는 컨트롤러가 호출되기 전에 실행된다.
    • 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.
    • return 값이 true면 다음 단계로 진행하지만, false라면 작업을 중단하여 이후의 작업은 진행되지 않는다.
  • postHandle
    • postHandle 메소드는 컨트롤러를 호출한 후에 실행된다.
    • 컨트롤러 이후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다.
    • View가 렌더링 되기 전 ModelAndView 조작이 가능하다.
    • 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하면 호출되지 않는다.
  • afterCompletion
    • 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다.
    • 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하더라도 반드시 호출된다.

 

Filter를 사용한 로그인 구현

  • 로그인을 Filter로 구현했을 때의 장점
    • 모든 요청에 대해 로그인 여부를 한 곳에서 일괄 체크할 수 있다. (Controller 마다 중복 코드 필요 없음)
    • Spring MVC 진입 전에 실행되므로 불필요한 리소스 낭비를 방지할 수 있다. (인증되지 않은 요청은 Controller까지 가지 않음)
public class LoginCheckFilter implements Filter {
    private static final String[] whiteListURLs = {"/login", "/signup"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        try {
            for (String url : whiteListURLs) {
                if (requestURI.equals(url)) {
                    chain.doFilter(request, response);  // 화이트리스트에 있는 URL은 필터를 통과
                    return;
                }
            }

            if (httpRequest.getSession().getAttribute("currentUser") == null) {
                httpResponse.sendRedirect("/login");
                return; // 로그인 되어 있지 않으면 다음으로 진행하지 않음
            }
            chain.doFilter(request, response);  // 다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출
        } catch (Exception e) {
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
        }
    }

}

 

 

참고글

https://mangkyu.tistory.com/18

'Spring' 카테고리의 다른 글

ArgumentResolver 종류 및 사용 예시  (1) 2025.05.07
Comments