Spring 🟢

filter와 Interceptor

minl741 2023. 8. 4. 21:24
패스트캠퍼스 남궁성님 강의 보고 정리하였습니다

filter란?

공통적인 요청 전처리와 응답 후처리에 사용됨(로깅, 인코딩 등)

  • 여러 서블릿들에서 위의 그림처럼, 공통적으로 발생하는 전처리, 후처리를 필터를 통해 중복 제거가 가능
    • 따라서 서블릿들에서는 본래의 맡은 처리만 즉 하나의 책임만 가질 수 있게 됨 

filter의 처리 과정

아래의 과정을 거쳐 요청이 처리된다고 할때 ( ->) 

처리되는 과정은 다음과 같다.

  1. 요청이 오면 처음 filter1의 전처리 진행
  2. filter2 호출
  3. filter2 전처리
  4. 서블릿 호출 후 메서드 처리
  5. filter2 후처리
  6. filter1 후처리

filter의 사용 예시

아래와 같은 서블릿이 있을 때, 전처리, 후처리 등 분리해야 할 코드가 보인다. 

  • ExampleServlet.java
@WebServlet("/abc")
public class ExampleServlet extends HttpServlet {
    public void service(HttpServletRequest request, HttpServletResponse response) {
        // 1. 전처리 작업
        long startTime = System.currentTimeMillis();

        // 2. 작업 로직

        // 3. 후처리 작업
        System.out.print("time = " + (System.cuurentTimeMillis() - startTime) + "ms");
    }
}

위와 같은 서블릿에서 전처리, 후처리 작업을 분리할 필터 예시는 아래와 같다.

  • PerformanceFilter.java
@WebFilter(urlPatterns = "/*") // 모든 요청에 PerformanceFilter를 적용.
public class PerformanceFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        // 1. 전처리 작업
        long startTime = System.currentTimeMillis();

        // 2. 서블릿(컨트롤러)또는 다음 필터 호출
        filterChain.doFilter(request, response);

        // 3. 후처리 작업
        long endTime = System.currentTimeMillis();
        System.out.print("["+ ((HttpServletRequest)request).getRequestURI()+"]");
        System.out.println(" time="+(endTime-startTime));
    }​

Interceptor란? 

쉽게 말해 servlet이 발전한 것이 controller라면, filter가 발전한 것이 Interceptor라고 생각하면 된다.

Interceptor 코드를 통해 이해하기

  1. HandlerInterceptor를 implements한 후에
  2. preHandle(전처리),  postHandle(후처리) 메서드를 구현
  3. @Component 어노테이션을 통해 컴토넌트 등록
@Component
public class PerformanceInterceptor implements HandlerInterceptor {
    // long startTime; // 인스턴스 변수임 -> 싱글톤(하나의 객체라) 여러 쓰레드가 하나의 객체를 공유
    // 따라서 지역 변수 보다는 request에 저장해서 공유하는 것이 낫다

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 전처리
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);

        // handler - 요청하고 연결된 컨트롤러의 메서드
        HandlerMethod method = (HandlerMethod) handler;
        System.out.println("method.getMethod() = " + method.getMethod()); // URL하고 연결된 메서드
        System.out.println("method.getBean() = " + method.getBean()); // 메서드가 포함된 컨트롤러

        // true를 리턴하면 다음 인터셉터 또는 컨트롤러가 호출
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (long) request.getAttribute("startTime");

        // 2. 후처리
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

  4.  WebMvcConfigurer를 implements한 @Configuration 클래스를 생성하고 

  5.  addInterceptors를 오버라이딩하여 해당 Interceptors를 추가해주면 됨!

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PerformanceInterceptor())
                .addPathPatterns("/**") // 인터셉터를 적용할 대상
                .excludePathPatterns("/css/**", "/js/**"); // 인터셉터 적용 제외대상
    }
}

filter와 Interceptor의 차이점

Interceptor가 filter에서 발전한 것은 알겠으나, 구체적으로 무엇이 다를까?

 

filter는 servletContext에 위치한 반면,

Interceptor는 WebApplicationContext에 위치하였는데 때문에 같은 WebApplicationContext에 있는 다른 Bean(자바 객체)들에 접근이 가능하다!