Spring은 공통적으로 여러 작업을 처리함으로써, 중복된 코드를 제거할 수 있도록 많은 기능을 지원하고 있습니다.
개 중에서, 필터(Filter) 와 인터셉터(Interfceptor) 를 정리합니다.
필터는 J2EE 표준 스펙 기능으로 디스패처 서블릿(Dispatcher Servlet) 에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공합니다.
디스패처 서블릿 은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위 밖에서 처리가 됩니다.
doFilter
메서드를 통해 필터 작업을 합니다.FilterConfig
에 접근이 가능하고,필터가 자리해야할 곳을 표시하고 서비스에 배치하기 위해 웹 컨테이너 로 부터 호출됩니다.
서블릿 컨테이너는 필터가 인스턴스화된 뒤 정확히 한번 호출합니다. 필터 작업을 하기전, 필터 초기화(init)가 성공적으로 완료되어야 합니다. 웹 컨테이너는 초기화 메서드가 1. ServletException
을 던지거나, 2. 웹컨테이너가 사전 지정한 시간 내에 종료(return)하지 않으면, 서비스에 배치 할 수 없습니다.
필터의 doFilter
메서드는 체인 끝의 리소스에 대한 클라이언트 요청으로 인해 요청/응답 쌍이 체인을 통과할 때마다 컨테이너에서 호출됩니다.
(좀 의역해보자면, 체인 끝의 리소스-> 디스패쳐 서블릿 이후 접근하고자 하는 리소스이므로, 클라이언트 요청/응답마다 필터 체인의 필터의 doFilter
메서드가 컨테이너에 의해 실행된다.. 정도)
이 메서드에 전달된 필터 체인 을 통해 필터 는 체인의 다음 개체 에 요청과 응답을 전달할 수 있습니다.
주로 이 메서드는 주로 다음과 같이 구현됩니다.
1. 요청값 검사
2. (옵션) 요청 객체를 입력 필터링
에 맞게 직접 구현한 필터 내용이나 헤더로 바꾸기
3. (옵션) 요청 객체를 출력 필터링
에 맞게 직접 구현한 필터 내용이나 헤더로 바꾸기
4. 아래 둘 중 하나 작업
1. FilterChain
객체를 이용하여 체인의 다음 개체(entity
)를 호출 (chain, doFilter()
)
2. 체인의 다음 객체에 요청/응답 값을 보내지 않고, 요청을 차단해버림
5. 필터 체인의 다음 개체를 호출하며 직접 헤더를 지정(set
)
웹 컨테이너가 서비스에서 필터를 제외시켰다는 것을 나타내기위해 호출합니다.
이 메서드는 필터들의 doFilter
메서드가 끝나거나, timeout
이 지났을 때 모든 쓰레드에서 한번만 호출됩니다.
웹 컨테이너가 이 메서드를 호출하면, 이 필터의 인스턴스에서 doFilter
를 다시는 요청하지 않습니다.
이 메서드는 필터에게 잡혀있는 자원(ex 메모리, 파일 핸들러, 쓰레드)을 모두 정리할 기회를 줍니다. 그리고 어떤 영속적인 상태도 메모리 상 필터의 현재 상태와 동기화되도록 합니다. (🤔 아마 모든 쓰레드에서 모두 동기화 된다는 의미인듯?)
먼저, 우리가 부르는 인터셉터들은 **HandlerInterceptor**
의 구현체이다. **HandlerInterceptor**
는 **HandlerMapping**
의 구현된 핸들러의 요청을 가로챈다(Intercept). 그래서, 공통된 요청을 가로질러 기능을 적용하고자 할때 유용하다.
HandlerInterceptor 인터페이스는 다음 세 메서드를 구현한다.
boolean
값을 반환하는 실제 핸들러가 실행되기 전 콜백 메서드이다. 만약 true
라면 계속 실행하고, false
라면 그 이후 실행 체인은 우회되고 핸들러가 실행되지 않는다
핸들러 실행 이후 콜백 메서드이다.
모든 요청이 끝난 뒤 콜백이다.
[추가]
인터셉터는 J2EE 표준 스펙인 [[Filter]]와 달리, Spring이 제공하는 기술로써 , 디스패쳐 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조/가공하는 기능을 제공한다. 즉, 웹 컨테이너(서블릿 컨테이너)에서 동작하는 필터와는 달리 인터셉터는 스프링 컨텍스트에서 동작한다. 디스패쳐 서블렛은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다. 그래서 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면, 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.
*HandlerMapping: @GetMapping
(이런식) 핸들러를 지정해주는 역할
디스패쳐 서블릿은 프론트 컨트롤러로서 핸들러 인스턴스를 맵과 같은 자료구조에 저장한다.
이후 url 패턴에 맞는 요청이 오면 해당 클래스를 반환 한 뒤 실행한다.