새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
TIL) 필터와 인터셉터 트레이드오프 비교하기
필터와 인터셉터 이해하기
필터와 인터셉터는 웹 요청과 응답을 처리할 때 공통 관심사를 처리하기 위한 추가 계층이라고 생각합니다.
공통 관심사를 AOP로 처리할 수 있지만 웹 관련 오브젝트인 HttpServletRequest
와 HttpServletResponse
그리고 인터셉터에게 주어지는 HandlerMapping
을 쉽게 제어하고 활용할 수 있게 제공하는 필터와 인터셉터가 적절합니다.
다른 개발자가 유지보수하고 확장할 때에도 웹 관련 공통 기능은 필터와 인터셉터에 추가하는 것이 설명이 없어도 웹 관련 공통 관심사라는 것을 알 수 있습니다.
구조로 이해하기
먼저 서블릿 컨테이너 레벨인 필터부터 확인해보면 다음과 같습니다.
필터 구조
★필터 체인은 요청마다 새로 만들게 됩니다.
음식점에서 여러 가지 재료를 준비해 놓고 메뉴(요청)이 들어오면 필요한 재료(필터)를 주방장(필터체인 팩토리)가 만들어놓습니다.
필터 체인 오브젝트는 동시성 이슈가 발생하지 않습니다. 웹 요청마다 새로운 객체를 만들기 때문이죠
그리고 필터 체인은 서블릿 컨테이너가 필터가 모두 순회되면 실행할 서블릿 정보도 전달합니다.
- 필터는 어떤 서블릿이 호출되는지 모른다.
- 필터 체인이 어떤 서블릿이 호출되는지 알고 있다.
우리가 작성하는 필터에서는 어떤 서블릿이 호출되는지 모르고, 어떤 응답 형식으로 반환할지 모릅니다.
필터는 서블릿들이 가지는 공통 관심사를 처리하기에 적합하다.
서블릿들은 어떤 공통 관심사를 가질 수 있을까 생각해보면
- 세션 관리
- 요청/응답에 대한 공통 처리: 인코딩, 파라미터 파싱, 응답 헤더 설정등
-
요청 이나 에러 핸들링: 서블릿에서 오류가 반환되는 경우 예외 처리를 할 수 있습니다.
- 토큰 및 헤더 검증
어떤 서블릿이 호출될지 모르는 데 비즈니스 레벨이 아니라 url
을 기준으로 필요한 토큰이나 헤더, 인코딩 타입등의 로직을 넣는 것이 적절하다고 생각됩니다.
인터셉터 구조
인터셉터는 서블릿이 호출되고 일치하는 핸들러(컨트롤러)가 있어야 실행이 됩니다.
인터셉터는 필터와 다르게 호출될 핸들러매핑 정보가 있습니다.
핸들러 정보를 통해서 메서드 이름, 클래스이름 , 파라미터, 어노테이션으로 세분화하여 실행여부를 결정할 수 있습니다.
인터셉터는 전역보다 핸들러 단위로 처리할 수 있는 세밀한 공통 로직을 넣을 수 있습니다.
생각 정리
소프트웨어 공학으로 필터는 상위 계층이고 서블릿은 하위 계층입니다.
필터는 서블릿 내부에 어떤 로직을 수행하는 지 모르고, 어떤 서블릿이 호출되는 지 모르는 상태입니다.
사용자의 요청 정보나 서블릿의 응답 정보에 대해 어떤 기능을 수행하는지 알 수 없습니다.
즉, 필터는 서블릿이 프론트 컨트롤러인 디스패처 서블릿이 호출되는지 알 수 없습니다.
그러면 필터는 서블릿이 호출되기 전에 어떤 공통 관심사를 갖는 것이 적절할까 생각했습니다.
- HTTP 레벨에서 헤더나 바디에 애플리케이션 레벨 수준에서 필수 값 유무 확인합니다.
- HTTP 레벨에서 인코딩이나 파일 압축이 가능합니다.
- 전역으로 요청/응답에 대한 로깅이 필요한 경우
서블릿 이후 인터셉터는 자신이 호출할 핸들러 매핑 정보, ModelAndView 정보, 예외 정보를 알 수 있습니다.
인터셉터는 핸들러의 내부 동작은 알 수 없어도 파라미터로 전달 받은 객체를 활용하여 공통 관심사를 처리할 수 있습니다.
필터는 HTTP 단위의 검증이라면 인터셉터는 핸들러 단위의 검증을 할 수 있습니다. 핸들러마다 다른 권한 설정이나 인증/인가, 로깅 그리고 필수 값 검증도 해결할 수 있습니다.
재진입과 생태 관리
필터는 재진입이 가능하여 doFilter
메서드 내에 필터 시작 전/ 후처리가 가능하기에 내부 상태를 지역변수를 통해서 설정할 수 있습니다.
하지만 인터셉터는 재진입이 불가하며 싱글톤으로 관리되기에 멤버 변수나 지역변수로 활용하여 상태 관리를 할 수 없습니다.
따라서 ThreadLocal이나 HttpSession
, Request.attribute
등을 활용할 수 있습니다.
디스패처 타입
필터는 was 레벨에서 동작하므로 포워드, 리다이렉트, 에러, 비동기와 같이 디스패처 타입(실행 제어 종류)에 따라 세분화하여 등록할 수 있습니다.
그러나 인터셉터도 물론 디스패처 타입을 확인할 수 있으나 핸들러 레벨에서는 주로 Request
타입으로 생각하고 동작합니다.
비즈니스 레벨은
필터는 네트워크에 가까운 공통 관심사라면 인터셉터는 비즈니스 연계와 데이터에 접근이 가능합니다.
사용자의 권한이나 리소스 접근 권한을 코드가 아니라 외부 네트워크를 활용할 수 있습니다.
예외처리
예외 처리를 생각하지 않을 수 없습니다.
예외 처리는 인터셉터나 필터에서 예외가 발생할 경우 누가 해결할 것인가입니다.
인터셉터에서 예외가 발생한다면 인터셉터를 호출한 스프링 MVC가 해결하거나 해결하지 못할 경우 was가 해결할 수 있습니다.
인터셉터 > 디스패처 서블릿 > 필터 > WAS
다만, 필터는 자신이 예외가 발생하는 경우에는 was가 해결해야합니다.
필터의 활용
필터는 디스패처 서블릿을 호출하지 않고 필터 검증에 따라 바로 종료할 수 있는 권한이 있습니다.
댓글남기기