Servlet 에서 제공하는 기능이자 스프링 프레임워크에서도 제공하는 기능이다. 말 그대로 앞단에서 무언가를 걸러줄 때 사용한다.
아래 그림은 대표적인 구성도다.
DisPatherServlet 앞단에서 존재하고 있고 DisPatherServlet이 요청과 응답을 다루기 전과 후에 동작을 한다.
위 그림만 보면 라이프 사이클이 예상 될 것이다.
클라이언트로부터 오는 모든 요청과 응답의 순수한 정보에 대해서 컨트롤 할 수 있다는 것을 기대한다.
특징
- 순수한 RequestBody와 ResponseBody를 확인을 할 수 있다.
- 유일하게 servletRequest, servletResponse의 객체를 변환 할 수 있다.
- 인증과 관련된 로직들을 해당 필터에서 처리한다.
왜 Filter 사용해야할까?
요청으로 들어온 정보에 노출되면 위험한 정보들이 들어 있을 수 있다.
이를 DispatcherServlet 이 처리하기 전에 filter에서 인코딩을 해주는 식과 인증, 인가 처리를 해야한다.
아직 security를 공부하지 않아 인증과 인가 관련해서 지식이 부족하다. 그러므로 filter의 사용 예시는 잘 모르겠다. security 를 배울 때 Filter를 적용하여 포스팅을 다시 해보겠다.
필터의 라이프 사이클
인터페이스 FIlter를 직접 구현하여 메서드를 오버라이딩 해보자.
필터가 동작하기 원한다면 @Component 를 붙여 bean으로 등록해야한다.
제일 먼저 실행되는 메서드는 init() 메서드가 호출 될 것이다.
다음으로 doFilter() 메서드가 호출되는데 doFilter() 는 매개변수로 ServletRequest 와 ServletResponse 를 받는 것에 주목하자.
우리는 이것을 가지고 데이터를 받아 볼 수 있다는 것이다.
다음으로 destroy() 메서드는 시스템이 종료 될 때 호출된다.
로그 그림을 보면 기대한것과 같게 호출 될 것이다.
필터 적용법
- @ServletComponentScan + @WebFilter
@SpringBootApplication 이 붙은 클래스에 @ServletComponentScan 을 선언한다.
더이상 FIlter를 구현한 곳에 @Component 를 선언하지 않아도 된다.
하지만 @WebFilter 라는 에노테이션을 선언 해줘야 한다.
Spring의 ComponentScan 원리와 같은 원리로 동작이 된다. @ServletComponentScan 이 @WebFilter
를 선언한 클래스를 읽어들여 Filter 등록을 해준다.
다음으로 urlPatterns 옵션에 필터를 적용 할 url를 넣어준다.
- @Bean 등록 + FilterRegistrationBean 등록
여러개의 Filter 를 등록 할 경우 bean으로 등록하여 사용 할 수 있고 setOrder() 으로 순서를 정할 수 있다. 매개변수 타입은 int 다.
다음으로 setUrlPatterns() 으로 특정 url 에 대해 필터를 적용할 수 있다. 매개변수 타입은 List<String> 이다
init() 호출은 setOrder() 과는 무관하게 호출이 되는 것 같다.
doFilter() 호출은 setOrder() 을 설정한 대로 호출이 된다.
destroy() 호출도 setOrder() 과는 무관하게 호출이 된다.
필터에 들어온 요청과 응답의 정보 Logging 하기 (전 처리 / 후 처리)
ServletRequest와 ServletResponse가 매개변수로 들어오면 ContentCachingRequestWrapper 과 ContentCachingResponseWrapper 에 의존성 주입 시켜 인스턴스를 생성한다.
ContentCachingRequestWrapper / ContentCachingResponseWrapper 를 사용하는 이유는 요청 응답에 대한 정보를 바이트 배열로 담아 필요할 때 꺼내 쓰기 위한 것이다.
다음으로 chain.doFilter(httpRequest, httpResponse) 을 호출 하고 후 처리 과정에서 요청 응답 정보를 담아 logging 작업을 한다.
반드시 후 처리 과정에서 정보를 가져와 logging 해야 한다.
ContentCachingRequestWrapper / ContentCachingResponseWrapper 는 인스턴스 생성 시점에 길이만 초기화되고 요청 응답 정보는 읽어 오질 않는다.
실제로 디버깅을 해보면 chain.doFilter() 가 호출이 된 후에 요청 응답 정보를 읽어온다.
이제 동작을 시켜 loggig 작업이 잘 되는지 확인하자
그런데 로깅은 잘 나오는데 응답 메시지가 내려오질 않는다.
ContentCachingRequestWrapper / ContentCachingResponseWrapper 는 내부에 Stream 기반 클래스들을 참조하여 동작하고 있다. Stream은 일회성이기 때문에 따로 바이트 배열을 복사를 해야한다.
ContentCachingResponseWrapper 는 복사 작업의 메서드를 제공하고 있다.
응답이 잘 나온것을 볼 수 있다.
'Spring Boot' 카테고리의 다른 글
@Builder 사용시 초기화 필드는 어떻게 될까? (0) | 2022.09.05 |
---|---|
[Spring boot] 순환 참조 이슈 (0) | 2022.08.12 |
[Spring Boot] Spring 에서 비동기 처리 방식은 어떻게 하고 왜 사용해야 할까? (0) | 2022.07.31 |
[Spring Boot] Interceptor 는 어떻게 사용하고 왜 사용해야 할까? (0) | 2022.07.30 |
[Spring Boot] Validation을 왜 해야하고 어떻게 할까? (0) | 2022.07.29 |
[Spring Boot] 예외처리를 왜 해야하고 어떻게 처리할까? (0) | 2022.07.29 |
ModelMapper (0) | 2022.07.20 |
[Spring Boot] Spring Dependency Injection 동작 원리와 Ioc Container를 알아보자 (0) | 2022.03.02 |