[ Spring ] 필터와 인터셉터

5tr1ker·2023년 5월 7일
0

Spring

목록 보기
4/10
post-thumbnail

필터 ( Filter )

필터는 J2EE 표준 스펙 기능으로 디스패처 서블릿에 요청이 전달되기 전/후에 URL 패턴에 맞는 모든 요청에 대해 부가 작업을 할 수 있는 처리할 수 있는 기능을 제공합니다. 디스패처 서블릿은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위 밖에서 처리됩니다.
즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너 ( 서블릿 컨테이너 ) 에 의해 관리가 되고 디스패처 서블릿 전/후로 처리가 됩니다.

필터의 메서드

필터를 구현하기 위해 javax.servlet 의 Filter 인터페이스를 구현해야 하며 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 메서드

init 메서드는 필터 객체를 초기화하고 서비스에 추가하는 메서드입니다. 웹 컨테이너가 init 메서드를 1회 호출하여 필터 객체를 초기화 하면 이후의 doFilter 메서드를 호출합니다.

doFilter 메서드

doFilter 메서드는 URL 패턴에 맞는 모든 HTTP 요청이 디스패처 서블릿에 전달되기 전에 웹 컨테이너에 의해 호출되는 메서드입니다. doFilter 의 파라미터로 FilterChain이 있는데 FilterChain의 doFilter 메서드를 통해 다음 대상으로 요청을 전달합니다. 따라서 chain.doFilter() 전/후로 필요한 처리과정을 추가할 수 있습니다.

destroy 메서드

destroy 메서드는 필터 객체를 서비스에서 제거하고 사용한 리소스를 반환하는 메서드입니다. 이는 웹 컨테이너에 의해 1회만 호출되고 이후에 doFilter에 의해 처리되지않습니다.

인터셉터 ( Interceptor )

인터셉터는 Spring이 제공하는 기술로, 디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청이나 응답을 참조하거나 가공할 수 있는 기술입니다. 웹 컨테이너 ( 서블릿 컨테이너 ) 에서 동작하는 필터와 달리 인터셉터는 스프링 컨테이너에서 동작합니다.

디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데 , 그 결과로 실행 체인 ( HandlerExecutionChain ) 을 반환합니다. 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터를 실행한 후에 컨트롤러를 호출하고, 인터셉터가 없다면 바로 컨트롤러를 호출합니다.

인터셉터는 스프링 컨테이너에서 동작하기 때문에 필터를 거쳐 디스패처 서블릿이 요청을 받은 후에 동작합니다.

실제로 Intercaptor 는 Controller 의 요청을 위임하지 않습니다. 아래의 그림은 순서를 도식화 한 것입니다.

인터셉터의 메서드

인터셉터를 추가하기 위해 org.springframework.web.servlet의 HandlerInterceptor 를 구현해야 하며 하단의 3가지 메서드를 가지고 있습니다.

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 메서드는 컨트롤러가 호출되기 전에 실행됩니다. 따라서 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 추가할 수 있습니다.
preHandle의 3번째 파라미터인 handler 는 핸들러 매핑이 찾아준 컨트롤러 빈에 매핑된 HandlerMethod 타입의 객체로 , @RequestMapping이 붙은 메서드를 추상화 한 객체입니다.
또한 preHandler의 반환 타입은 Boolean 인데 true 값이면 다음 단계로 진행되지만 , false 이면 작업을 중단합니다. ( 다음 인터셉터 또는 컨트롤러 )

postHandle 메소드

PostHandle은 컨트롤러가 호출된 후에 실행됩니다. 그렇기 때문에 컨트롤러 호출 후 처리해야 하는 후처리 작업이 있을 때 사용합니다.
postHandle 메서드의 3번째 파라미터는 컨트롤러가 반환하는 ModelAndView 를 제공하는데, 최근에 Json 형태로 정보를 제공하는 RestAPI를 사용하면서 자주 사용되지 않습니다.
또한 컨트롤러 하위 계층에서 예외가 발생하면 postHandler는 호출되지 않습니다.

afterCompletion 메소드

afterCompletion 은 요청에 대한 모든 작업이 완료된 이후에 실행됩니다. 요청 처리 중에 사용된 리소스를 반환하기에 적합합니다.
postHandle 과 달리 컨트롤러 하위 계층에 예외가 발생해도 afterCompletion 메서드는 반드시 호출됩니다.

인터셉터와 AOP 비교

인터셉터 대신에 컨트롤러에 적용할 부가기능을 어드바이스로 만들어 AOP 를 적용할 수 있습니다. 하지만 다음과 같은 이유로 컨트롤러에 적용할 부가기능들은 인터셉터를 사용하는 것이 낫습니다.
1. 컨트롤러는 타입과 실행 메서드가 모두 달라 포인트컷을 작성하기 어렵습니다.
2. 컨트롤러는 리턴과 파라미터 값이 일정하지 않습니다.
3. AOP 에서는 HttpServletRequest / HttpServletResponse 객체를 얻기 힘들지만 인터셉터는 파라미터로 넘어옵니다.

인터셉터 vs 필터 차이

관리 컨테이너

위의 그림처럼 필터와 인터셉터는 관리되는 컨테이너가 다릅니다. 필터는 스프링 이전인 서플릿 영역에서 관리되며, 인터셉터는 스프링 영역에서 관리됩니다. 그렇기 때문에 필터는 스프링이 처리하는 작업을 적용할 수 없으며 이로 인해 발생하는 문제 중 하나가 필터는 스프링에 의한 예외처리가 되지 않는다는 것입니다.

Request / Response 객체 조작

필터는 Request 와 Response 객체를 조작할 수 있지만 인터셉터는 조작할 수 없습니다. 여기서 조작은 내부 상태가 변경되는 것이 아니라 다른 객체로 바꿔치는 것을 말합니다.

필터는 다음 필터를 호출하기 위해서 필터 체이닝을 해주어야 하며 , 이때 개발자가 만든 Response와 Request 객체를 넘겨줄 수 있습니다.

public MyFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 개발자가 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse());       
    }
}

하지만 인터셉터는 필터와 처리 과정이 다릅니다. 디스패처 서블릿이 여러 인터셉터들을 차례대로 호출하고 true 값이면 다음 인터셉터를 호출하거나 컨트롤러를 호출하고 false 값이면 요청이 중단됩니다. 따라서 우리는 Request / Response 객체를 넘겨줄 수 없습니다.

public class MyInterceptor implements HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Request/Response를 교체할 수 없고 boolean 값만 반환할 수 있다.
        return true;
    }

}

필터와 인터셉터의 용도

필터의 용도 및 예시

  1. 공통된 보안 및 인증/인가 관련 작업
  2. 모든 요청에 대한 로깅과 감사
  3. 이미지/데이터 압축 및 문자열 인코딩
  4. Spring 과 분리되어야 하는 기능

공통된 보안은 올바르지 않은 요청을 차단하여 안정성을 높일 수 있습니다. 또한 웹 어플리케이션에 전반적으로 사용되는 기능을 구현할 수 있습니다.

인터셉터의 용도 및 예시

  1. 세부적인 보안 및 인증/인가 공통 작업
  2. API 호출에 대한 로깅과 감사
  3. Controller로 넘겨주는 데이터를 가공

특정 그룹이 사용하지 못하는 기능이 있는데 이러한 작업을 컨트롤러로 넘어가기 전에 처리할 수 있으며, 또한 Request 와 Response 의 객체를 조작할 수 없지만 내부적으로 갖는 값을 조작할 수 있으므로 컨트롤러에게 넘겨주는 정보를 가공할 수 있습니다.

함께 읽으면 좋은 블로그

참고 블로그 1 : https://mangkyu.tistory.com/221

참고

참고 블로그 1 : https://mangkyu.tistory.com/173

profile
https://github.com/5tr1ker

0개의 댓글