Develop/Spring

[Spring]Filter와 Interceptor의 개념 및 차이

롱하 2024. 10. 17. 16:35

 

개발을 하다보면 공통적으로 처리해야할 것들이 많은데, 이러한 공통적인 업무에 관련된 코드를 페이지 마다 작성한다면 중복코드가 많아지게 되고 프로젝트 단위가 커질수록 서버에 부하를 줄 수 있으며, 소스 관리가 되지 않을 수 있다.

 

이에 따라 Spring에서는 공통적으로 여러작업을 처리함으로써 중복된 코드를 제거할 수 있는 다음과 같은 기능들을 지원하고있다.

 

1. Filter

2. Interceptor

3. AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)
* Spring에서 사용되는 위의 3가지 기능들은 모두 어떠한 행동을 하기 전에 먼저 실행하거나, 실행한 후에 추가적인 행동을 할 때 사용하는 기능들이다.

 

먼저 Filter와 Interceptor의 개념과 차이점을 알아보고 Interceptor과 AOP에 대해서도 비교해보려고한다.

 

1. 필터(Filter)

필터는 말 그대로 요청과 응답을 거른뒤 정제하는 역할을 한다.

Dispatcher Servlet에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공한다.

 

즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너에 의해 관리가 되는것이고, 스프링 범위 밖에서 처리되는 것(스프링 빈으로 등록 가능)

 

 

 

  • Filter의 메서드 종류 및 예시
package javax.servlet;

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() {}
}

 

필터는 Servlet 컨테이너 레벨에서 작동하며, HTTP 요청 및 응답에 대한 처리를 수행한다.

스프링에서 필터 인터페이스의 패키지를 보면 javax.servlet에 위치하고 있는것을 알 수 있는데 스프링 프레임워크와는 무관하게 서블릿 컨테이너 레벨에서 작동한다는 것이다.

 

즉, 필터는 서블릿이 지원하는 수문장이고, 필터를 적용하면 필터가 호출된 다음에 서블릿이 호출된다. 그래서 만약 모든 고객의 요청 로그를 남기는 요구사항이 있다면 필터를 사용하면 된다.

 

  • init() :

필터 객체를 초기화하고 서비스에 추가하기 위한 메서드이다.

웹 컨테이너가 1회 init()을 호출하여 필터 객체를 초기화하면 이후 요청들은 doFilter()를 통해 처리된다.

  • doFilter() :

url-pattern에 맞는 모든 HTTP 요청이 Dispatcher Servlet으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메서드이다.

doFilter의 파라미터에 FilterChain이 있는데, FilterChain의 doFilter()를 통해 다음 대상으로 요청을 전달할 수 있게 된다. chain.doFilter()로 전, 후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있다.

  • destroy() : 

필터 객체를 제거하고 사용하는 자원을 반환하기 위한 메서드이다.

웹 컨테이너가 1회 destroy()를 호출하여 필터 객체를 종료하면 이후에는 doFilter에 의해 처리되지 않는다.

 

2. 인터셉터(Interceptor)

 

간단히 말하자면 요청에 대한 작업 전/후로 가로챈다고 보면 된다.

 

Dispatcher Servlet이 Controller를 호출하기 전/후에 Interceptor가 끼어들어 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.

 

웹 컨테이너에서 동작하는 필터와 달리 인터셉터는 스프링 컨텍스트에서 동작한다. 

 

 

Interceptor는 HandlerInterceptor인터페이스를 구현해서 사용할 수 있다. 

 

  • HandlerInterceptor
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의 패키지를 보면 org.springframework.web.servlet에 위치하고 있다. 즉, 스프링 컨텍스트 내부에서 작동한다는 것이다.

Dispatcher Servlet은 내부적으로 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데 그 결과로 HandlerExecutionChain을 반환한다.

 

여기서 1개 이상의 Interceptor가 등록되어 있다면 순차적으로 인터셉터를 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.

 

  • preHandle : 반환값으로 true/false를 반환하는데, true일 경우 다음 인터셉터를 호출하고 false인 경우 요청을 종료
  • postHandle : 컨트롤러가 호출된 직후에 실행
  • afterCompletion : 요청이 완료된 (뷰 응답) 이후에 실행

 

+ Interceptor와 AOP의 비교

인터셉터 대신에 컨트롤러에 적용할 부가기능을 어드바이스로 만들어 AOP를 적용할 수도 있다.

하지만 다음과 같은 이유들로 컨트롤러의 호출 과정에 적용되는 부가기능들은 인터셉터를 사용하는편이 낫다.

 

1. 컨트롤러는 타입과 실행 메서드가 모두 제각각이라 포인트컷(적용할 메서드 선별)의 작성이 어렵다.

2. 컨트롤러는 파라미터나 리턴값이 일정하지가 않다.

 

즉, 타입들이 일정하지 않고 호출 패턴도 정해져 있지 않기 때문에 컨트롤러에 AOP를 적용하려면 번거로운 부가 작업들이 생기게 된다.

 

3. Filter와 Interceptor의 차이 및 비교

 

그렇다면 Filter와 Interceptor 둘 중에 어떤걸 사용해야 할까?

 

가장 중요한 기준은 어떤 시점에 사용할것인가가 중요하다.

 

필터(Filter)는 서블릿에서 처리하는 과정의 전후를 다룰 수 있으므로 스프링과는 무관하게 전역적으로 처리하는 작업들을 수행할 때 사용할 수 있다.

웹 애플리케이션의 전반적인 요청 처리 및 보안 설정

(ex : 요청의 로그 남기기, 인코딩, 요청 필터링, CORS 처리 등)

 

인터셉터(Interceptor)인터셉터는 스프링 내부에서 컨트롤러가 처리하는 과정의 전/후를 다룰 수 있으므로 컨트롤러에 넘겨주는 데이터를 가공하거나 처리할 때 사용할 수 있다.

비즈니스 로직을 처리하는 데 집중하며, 특정 컨트롤러 전후에 실행되는 로직

(ex : 인증, 권한 체크, 데이터 처리 등)

 

* 두 개념 모두 요청 전후 처리를 수행하지만, Filter는 더 넓은 범위의 요청을 처리하고, Interceptor는 컨트롤러 레벨의 세부적인 처리를 담당하는 데 차이가 있다.