[Spring] 서블릿 필터와 스프링 인터셉터

윤경·2022년 8월 18일
0

SpringBoot

목록 보기
2/3

공통 관심사, cross-cutting concern

: 애플리케이션 여러 로직에서 공통으로 관심이 있는 것

스프링의 AOP로도 해결할 수 있지만 웹과 관련된 공통 관심사는 서블릿 필터 또는 스프링 인터셉터를 사용하는 것이 좋다.
(스프링 MVC를 사용하고 있으며 꼭 필터가 필요한 상황이 아니라면 스프링 인터셉터를 사용하기)

이들을 사용하려면 HTTP Header나 URL 정보들이 필요한데 서블릿 필터와 스프링 인터셉터는 HttpServletRequest를 제공한다.

서블릿 필터, Servlet Filter

: 서블릿이 지원하는 수문장으로 디스패처 서블릿에 요청 전달 전/후 URL 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있다.

디스패처 서블릿은 스프링의 가장 앞단 컨트롤러필터는 스프링 범위 밖에서 처리된다.

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러

필터를 적용하면 서블릿 전 필터가 먼저 호출되기 때문에 어떠한 기능 이전 공통된 관심사를 해결할 때 필터를 사용하면 된다. (Ex. 로그인 기능)

그리고 필터는 여러개로 구성될 수 있다. (Ex. 로그 남기는 필터 -> 로그인 여부 체크 필터 -> ... )

서블릿 필터를 사용하기 위해서는 필터 인터페이스에 있는 init(), doFilter(), destroy() 메소드를 구현해야 한다.

  • init()
    : 필터를 초기화하는 메소드로 서블릿 컨테이너가 생성될 때 호출
  • doFilter()
    : 요청시마다 호출되며 필터의 로직을 이 곳에 구현
  • destroy()
    : 필터를 종료하는 메소드로 서블릿 컨테이너가 종료될 때 호출
  • chain.doFilter(request, response);
    : 다음 필터가 있다면 호출, 없다면 서블릿 호출
    이 로직을 호출하지 않는다면 다음 단계를 진행 할 수 없다.

스프링부트에서의 필터 등록은 FilterRegistrationBean을 사용하면 된다.

스프링 인터셉터, Spring Interceptor

: 서블릿 필터와 같이 웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기능으로 스프링이 제공한다.
즉, 스프링 컨텍스트 안에서 동작하며 디스패처 서블릿이 컨트롤러 호출 전/후 요청/응답을 참조하거나 가공할 수 있는 기능을 가지고 있다.

디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하며 이 결과로 실행 체인(HandlerExecutionChain)을 반환해준다.

실행 체인은 1개 이상의 인터셉터가 등록 되어있다면, 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되며 한 개의 인터셉터도 등록되어 있지 않다면 바로 컨트롤러를 실행한다.

  • 서블릿 필터
    : 서블릿이 제공
  • 스프링 인터셉터
    : 스프링 MVC가 제공

공통점: 둘 다 웹과 관련된 공통 관심 사항을 처리
차이점: 적용되는 순서와 범위, 사용방법이 다름

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

스프링 인터셉터는 컨트롤러 호출 직전 호출된다.
스프링 MVC의 시작점이 디스패치 서블릿이고 스프링 인터셉터는 스프링 MVC가 제공하는 기능이기 때문에 결국 디스패처 서블릿 이후 등장하는 것이다.

그리고 스프링 인터셉터 또한 체인 형식을 적용할 수 있다. (인터셉터1 -> 인터셉터2 -> ...)

스프링 인터셉터가 서블릿 필터보다 편하고 정교하며, 더 다양한 기능을 지원한다.
(서블릿 필터doFilter()만 제공하지만,
인터셉터preHandler, postHandler, afterCompletion 이렇게 단계적으로 세분화시켜 제공한다.
또한, 서블릿 필터는 request, response만 제공했지만,
인터셉터는 어떤 컨트롤러(핸들러)가 호출되는지 호출 정보까지 받을 수 있으며 어떤 modelAndView가 반환되는지 응답 정보도 받을 수 있다.)

스프링 인터셉터를 사용하기 위해서는 HandlerInterceptor 인터페이스를 구현해야 한다.

  • preHandler
    : 컨트롤러 호출 전 호출(핸들러 어댑터 호출 전)
  • postHandler
    : 컨트롤러 호출 후 호출(핸들러 어댑터 호출 후)
  • afterCompletion
    : 뷰가 렌더링 된 이후 호출(항상 호출, 예외를 파라미터로 받아 어떤 예외가 발생했는지 로그 출력 가능)

위에서도 언급했듯 인터셉터는 스프링 MVC 구조에 특화된 필터 기능을 제공하기 때문에 스프링 MVC를 사용하며 특별히 꼭 그 필터를 사용해야 하는 것이 아니라면 인터셉터를 사용하는 것이 좋다.


Java instanceOf 연산자

: 객체가 어떤 클래스인지 어떤 클래스를 상속 받았는지 확인하는 연산자

object instanceOf type 형태로 사용
Ex. if(handler instanceOf HandlerMethod) {...}

  • HandlerMethod
    : @Controller, @RequestMapping을 활용해 핸들러 매핑을 사용하면 핸들러 정보로 HandlerMethod가 넘어옴
  • RequestHttpRequestHandler
    : /resource/static과 같은 정적 리소스가 호출되는 경우 RequestHttpRequestHandler가 핸들러 정보로 넘어옴

그러므로 타입에 따라 각각 처리가 필요하다.

Spring Argument Resolver

서비스 운영시 다양한 데이터 종류를 다루어야 한다.
컨트롤러 부분에서 이를 전처리 할 때 코드를 함수화 하는데 이 함수를 계속 호출할 수도 없다.

그래서 스프링에서는 파라미터를 공통으로 처리할 수 있도록 구현한 ArgumentResolver 인터페이스가 있다.

  • HandlerMethodArgumentResolver
    : 인터페이스.
    컨트롤러의 인자에 지정된 변수들을 어노테이션이나 객체의 타입에 따라 resolver를 먼저 거쳐 실제 데이터를 컨트롤러에 넘겨주는 역할을 수행한다.

컨트롤러에 들어오는 인자를 가공/추가/수정하는 경우 사용한다.

이를 사용하면 매개변수로 사용되는 인자에 대하여 공통 처리 로직이 있을 경우 중복 코드를 줄여 코드를 간결하게 만들 수 있다.

profile
개발 바보 이사 오는 중

0개의 댓글