Interceptor와 filter

?에서 !로·2022년 3월 17일
0

필터, 인터셉터가 필요한 이유

스프링 코드를 프로그램을 구현할 때 공통적으로 처리해야할 업무들이 많다. 공통업무에 관련된 코드를 모든 페이지 마다 작성해야한다면 중복된 코드가 많아지게 되면 소스관리가 힘들어진다.

스프링에서 공통처리를 위해 다음을 활용할 수 있다.

  • Filter
  • Interceptor
  • AOP

filter

서블릿 필터는 서블릿 실행 전, 후에 어떤 작업을 하고자 할때 사용한다. 그래서 DispatcherServlet 앞단에서 실행이 되며 즉, 스프링 컨테이너 밖에 위치한다. 클라이언트와 자원 사이에 여러 필터가 모여서 하나의 체인으로 구성되어 있다. 대표적으로 인코딩 변환처리, XSS 방어, LOG, 보안, 이미지변환, 데이터압축, 캐시 등을 구현할때 사용한다.

  • 스프링 컨테이너에 존재하는 빈들을 사용할 수 없어 비즈니스 로직과 연관된 작업을 수행할 수 없다.
  • 환경 설정은 주로 톰캣을 사용할 경우 web.xml 또는 Java Configuration 을 이용해서 구현할수 있다.

구현

필터를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현(implements)해야 하며, 3가지 메소드를 가지고 있다.

  • init 메소드는 필터객체를 초기화하고 서비스에 추기하기 위한 메소드이다. 웹 컨테이너가 1회 init 메소드를 호출하여 필터 객체를 초기화하면 이후의 요청들은 doFilter를 통해 처리된다.
public default void init(FilterConfig filterConfig) throws ServletException {}
  • doFilter 메소드는 url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메소드이다. doFilter의 파라미터로는 FilterChain이 있는데, filterChain은 다음 필터를 가리키고 filterChain.doFilter()는 다음 필터를 호출한다. 다음 필터가 없다면 내부적으로 서블릿의 service()를 호출한다. chain.doFilter() 전/후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있다.
public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException;
  • destroy 메소드는 필터 객체를 웹 컨테이너에서 제거하고 사용하는 자원을 반환하기 위한 메소드이다. 이는 웹 컨테이너에 의해 1번 호출되며 이후에는 이제 doFilter에 의해 처리되지 않는다.

동작방식

① 서블릿 컨테이너는 웹 어플리케이션을 시작할 때 DD파일(web.xml)에 등록된 필터의 인스턴스를 생성하고 init()을 호출한다.

② 클라이언트 요청이 들어오면 해당하는 필터의 doFilter()를 호출한다.

③ doFilter()에서 작업을 실행하고 다음 필터의 doFilter()를 호출한다.

④ 마지막 필터까지 ③을 반복한다.

⑤ 마지막 필터는 서블릿의 service()를 호출한다.

⑥ 서블릿의 service()가 끝나면 service()를 호출했던 이전 필터로 돌아간다.

⑦ 반복해서 제일 처음 호출됐던 필터까지 돌아간다.

⑧ 마지막으로 클라이언트에게 응답 결과를 보낸다.

Interceptor

인터셉터는 Spring이 제공하는 기술로써, 디스패처 서블릿이 Controller(Handler)를 호출하기 전, 후에 요청과 응답에 특정 작업을 처리할 수 있다.

  • 디스패처 서블릿은 핸들러 매핑을 통해 컨트롤러를 찾는데, 이때 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.
  • 환경 설정은 주로 servletContext.xml 또는 Java Configuration 을 이용해서 구현

대표적으로 인증/인가 등과 같은 공통작업, controller로 넘겨주는 정보의 가공, 로그인 처리 시 많이 사용된다.

구현

인터셉터를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현해야 하며, 다음의 3가지 메소드를 가지고 있다.

  • preHandle 메소드는 컨트롤러가 호출되기 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.
 default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception 
 { return true; }
  • postHandle 메소드는 컨트롤러를 호출된 후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다. 이 메소드에는 컨트롤러가 반환하는 ModelAndView 타입의 파라미터가 제공되는데, 최근에는 Json 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지는 않는다.

  • afterCompletion 메소드는 이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다. 요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다.

동작방식

  1. DispatcherServlet이 클라이언트 요청을 받는다.

  2. HandlerMapping으로 부터 주어진 request를 처리할 수 있는 Handler객체를 가져온다.

  3. 가져온 Handler를 실행(invoke) 시킬 수 있는 HandlerAdapter객체를 할당

  4. 해당 Controller를 처리할 Handler객체에 적용할 interceptor가 존재한다면, prehandle 메소드를 호출

  5. 컨트롤러의 메소드를 실행 후 ModelAndView를 얻는다.

  6. postHandle

  7. ModelAndView를 통해 view name을 ViewResolver에게 전달하여 응답에 필요한 View객체를 얻어온다.

  8. View객체에 Model을 파라미터로 넘겨주어 render메소드를 호출

  9. afterCompletion

예외 흐름

preHandle이 예외를 발생시키면 뒤에 있던 postHandle이 호출되지 않는다. 하지만 afterCompletion은 항상 호출이 된다.

Filter VS Interceptor VS AOP

필터와 인터셉터

  • 실행 시점

    • 필터는 Web 컨테이너 위치 하고, Interceptor는 Spring 컨테이너에 위치 한다.
    • Filter는 Dispatcher servlet의 앞단에서 정보를 처리하고,
    • Dispatcher servlet에서 Handler(Controller)의 사이에서 정보를 처리한다.
  • 작업 범위

    • 필터에서는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다. (ServletRequest/ServletResponse 객체를 조작할 수 있다)
    • Interceptor는 스프링 컨테이너 안에서 스프링내의 모든 객체에 접근이 가능하다.
    • Interceptor는 HttpServletRequest나 HttpServletResponse 등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없다. 대신 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이하다.
  • 사용 영역 : 주로 인코딩이나 보안 관련 처리와 같은 web app의 전역적으로 처리해야 하는 로직은 필터로 구현하고 클클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업에 대해서는 주로 인터셉터에서 처리한다.

대표적으로 필터(Filter)를 인증과 인가에 사용하는 도구로는 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 Spring MVC에 종속적이지 않다는 것인데, 이러한 이유로는 필터 기반으로 인증/인가 처리를 하기 때문이다.

인터셉터와 AOP 차이

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

하지만,

  1. Spring의 컨트롤러는 타입과 실행 메소드가 다양하여 포인트컷(적용할 메소드 선별)의 작성이 어렵다.
  2. Spring의 컨트롤러는 파라미터나 리턴 타입이 일정하지 않다.

따라서, 컨트롤러에 AOP를 적용하려면 복잡할 수 있어 부가기능들은 인터셉터를 사용하는 편이 낫다.

0개의 댓글