스프링 인터셉터

흐름

서블릿 필터가 서블릿이 제공하는 기술이라면 스프링 인터셉터는 스프링 MVC가 제공한다. 둘 다 웹의 공통 관심 사항얼 처리하지만 순서, 범위, 방법이 다르다.

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
  • 스프링 인터셉터는 서블릿과 컨트롤러 사이에서 호출된다.

  • 스프링 인터셉터가 스프링 MVC의 기능이므로 여기서의 서블릿은 디스패처 서블릿을 의미한다.

    • 스프링 MVC의 시작점이 디스패처 서블릿이라고 생각해보면 결국 스프링 인터셉터는 디스패처 서블릿 이후에 등장하는 게 맞다.

  • URL 패턴을 적용할 수 있다.

    • 서블릿 URL 패턴과는 다르다.

    • 아주 정밀하게 설정할 수 있다.

제한

  • 로그인 사용자

    • HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러

  • 비로그인 사용자

    • HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터

    • 적절하지 않은 요청이라 판단하고 컨트롤러를 호출하지 않는다.

적절하지 않은 요청은 컨트롤러 직전에 끝낼 수 있으므로 로그인 여부를 체크하기 좋다.

체인

  • 체인으로 구성된다.

  • 중간에 인터셉터를 자유롭게 추가할 수 있다.

HandlerInterceptor

서블릿 필터는 doFilter()만 단순하게 호출하고 실수로 호출을 안해서 에러가 나는 경우도 있다. 스프링 인터셉터는 좀 더 세분화 되어 있다.

  • preHandle()

    • 컨트롤러 호출 전

  • postHandle()

    • 컨트롤러 호출 후

  • afterCompletion()

    • 요청 완료 이후

또, 서블릿 필터는 request, response만 제공했지만 스프링 인터셉터는 다양한 정보를 받을 수 있다.

  • handler

    • 호출 정보

    • 어떤 컨트롤러가 호출되는지

  • modelAndView

    • 응답 정보

    • 어떤 modelAndView가 반환되는지

호출 흐름

  1. preHandle

    • 핸들러 어댑터 및 컨트롤러 호출 전에 호출한다.

    • preHandle의 응답이 true면 다음으로 진행한다.

    • false면 나머지 인터셉터와 핸들러 어댑터 모두 호출되지 않고 여기서 끝난다.

  2. handle(handler)

  3. ModelAndView 반환

  4. postHandle

    • 핸들러 어댑터 및 컨트롤러 호출 후에 호출한다.

  5. render(model)

  6. afterCompletion

    • 뷰가 렌더링 된 이후 호출한다.

예외 상황

  1. preHandle

    • 컨트롤러 호출 전에 호출되므로 예외 발생 여부와 상관 없이 실행된다.

  2. handle(handler)

  3. ModelAndView 반환

  4. postHandle

    • 컨트롤러에서 예외가 발생하면 호출되지 않는다.

  5. render(model)

  6. afterCompletion

    • 예외와 무관하게 항상 호출된다.

    • 예외를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.

    • 예외와 무관하게 공통 처리를 하려면 여기를 이용해야 한다.

스프링 인터셉터는 스프링 MVC 구조에 특화된 필터 기능이다. 스프링 MVC를 사용하고 특별히 필터를 써야 하는 상황이 아니라면 인터셉터를 사용하는 게 더 편하다.

요청 로그 인터셉터 구현하기

  • uuid

    • 요청 로그를 구분하기 위해 생성한다.

  • request.setAttribute(LOG_ID, uuid)

    • 서블릿 필터는 지역 변수로 해결할 수 있지만 스프링 인터셉터는 호출 시점이 완전 분리되어 있어 불가하다.

    • 다른 메서드에서도 함께 사용하려면 request에 담아두면 된다.

      • LogInterceptor는 싱글톤처럼 사용되기 때문에 멤버 변수로 사용하면 위험하다.

  • return true

    • 정상 호출

    • 다음 인터셉터나 컨트롤러가 호출된다.

  • afterCompletion()

    • 예외 발생 시 postHandle()은 호출되지 않기 때문에 여기에 종료 로그를 남긴다.

handlerMethod

  • 어떤 핸들러 매핑을 사용하는가에 따라 핸들러 정보가 달라진다.

    • 일반적으로 @Controller, @RequestMapping으로 핸들러 매핑을 사용한다.

    • 이 경우 핸들러 정보로 HandlerMethod가 넘어온다.

  • ResourceHttpRequestHandler

    • @Controller 대신 /resources/static 같은 정적 리소스는 여기로 핸들러 정보가 넘어온다.

인터셉터 등록

  • WebMvcConfigurer의 addInterceptors()으로 인터셉터를 등록한다.

  • addPathPatterns()

    • 인터셉터를 적용할 URL 패턴 지정

  • excludePathPatterns()

    • 인터셉터에서 제외할 패턴 지정

PathPattern 공식 문서

  • LoginCheckFilter 뒤에 LogInterceptor가 실행되었다.

    • ModelAndView부터 핸들러 정보, Member, Model 등의 파라미터 정보까지 다 찍힌다.

인증 체크 인터셉터 구현하기

  • 인증은 컨트롤러 호출 전에만 한 번 하면 되므로 preHandle()만 구현한다.

    • 서블릿과 달리 메서드가 나눠져 있어 관심사에 따라 분리할 수 있어 편하다.

  • 서블릿보다 간단하게 패턴을 적용할 수 있다.

    • 화이트 리스트에 따른 복잡한 로직을 수행하지 않는다.

  • 로그와 로그인 모두 인터셉터로 처리되었다.

서블릿 필터와 스프링 인터셉터는 웹의 공통 관심사를 해결하기 위한 기술이지만 스프링 인터셉터가 개발자 입장에서 훨씬 편리하므로 인터셉터를 주로 사용하는 게 좋다.

참고로 필터와 인터셉터 모두 빈으로 등록해서 @Autowired로 주입받아 사용할 수도 있다.

Last updated

Was this helpful?