서블릿 필터Servlet Filter
:서블릿 기반 애플리케이션의 엔드포인트에 요청이 도달하기 전에 중간에서 요청을 가로챈 후 어떤 처리르 할 수 있도록 해주는 Java 컴포넌트
:서블릿 기반 애플리케이션에서의 Filter 위치
:위 그림처럼 클라이언트가 서버 측 애플리케이션으로 요청을 전송하면 제일 먼저 Servlet Filter를 거치게 됨. 그리고 Filter에서의 처리가 모두 완료되면 DispatcherServlet에서 클라이언트의 요청을 핸들러 메서드에 매핑하기 위한 다음 작업을 진행함
:여러개의 Filter가 체인을 형성하고 있는 Filter 묶음을 의미함
1)Servlet FilerChain은 요청 URL path를 기반으로 HttpServletRequest를 처리함
따라서 클라이언트가 서버 측 애플리케이션에 요청을 전송하면 서블릿 컨테이너는 요청 URL의 경로를 기반으로 어떤 Filter와 어떤 Servlet을 매핑할지 결정함
2)Filter는 Filter Chain 안에서 순서를 지정할 수 있으며 지정한 순서에 따라서 동작하게 할 수 있음
3)Filter Chain에서 Filter의 순서는 매우 중요
Spring Boot에서 여러개의 Filter를 등록하고 순서를 지정하기 위해서는 다음 두 가지 방법 적용 가능
a. Spring Bean으로 등록되는 Filter에 @Order 애너테이션을 추가하거나 Order 인터페이스를 구현해서 Filter의 순서 지정 가능
b. FilterRegistrationBean을 이용해 Filter 순서를 명시적으로 지정 가능
public class FirstFilter implements Filter {
// 1) 초기화 작업
public void init(FilterConfig filterConfig) throws ServletException {
}
// 2)
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// 2-1) 이 곳에서 request(ServletRequest)를 이용해 다음 Filter로 넘어가기 전처리 작업을 수행한다.
// 2-2)
chain.doFilter(request, response);
// 2-3) 이 곳에서 response(ServletResponse)를 이용해 response에 대한 후처리 작업을 할 수 있다.
}
// 3)
public void destroy() {
// 5) Filter가 사용한 자원을 반납하는 처리
}
}
:Servlet Filter 인터페이스를 구현한 구현 클래스의 기본 구조
1) public void init(FilterConfig filterConfig) throws ServletException {...}
:생성한 Filter에 대한 초기화 작업을 진행할 수 있음
2) public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException{...}
:doFilter() 메서드에서 해당 Filter가 처리하는 실질적 로직 구현
2-1)
:request를 이용해 2-2) chain.doFilter(request, response)가 호출되기 전에 할 수 있는 전처리 작업에 대한 코드를 구현
2-3)
:response를 이용해 2-2) chain.doFilter(request, response) 호출된 후에 할 수 있는 후처리 작업에 대한 코드를 구현
3) public void destroy() {...}
:Filter가 컨테이너에서 종료될 때 호출됨
:주로 Filter가 사용한 자원을 반납하는 처리 등의 로직을 작성하고자 할 때 사용
import javax.servlet.*;
import java.io.IOException;
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("FirstFilter 생성됨");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("========First 필터 시작========");
chain.doFilter(request, response);
System.out.println("========First 필터 종료========");
}
@Override
public void destroy() {
System.out.println("FirstFilter Destory");
Filter.super.destroy();
}
}
import book.study.security.FirstFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegister() {
FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
return registrationBean;
}
}
:Spring Boot에서 Servlet Filter는 위 코드와 같이 FilterRegistrationBean의 생성자로 Filter 인터페이스의 구현 객체를 넘겨주는 형태로 등록할 수 있음<노이해중>
애플리케이션 실행 시 가장 먼저 init() 메서드 실행되며 아래 로그 출력됨
FirstFilter 생성됨
다음으로 만든 Controller가 있다면 해당 컨트롤러의 핸들러 메서드로 요청을 보내기
doFilter -> controller 동작 -> destroy 메서드 형태로 Filter 동작하며 아래와 유사한 로그 출력
========First 필터 시작========
Hello
========First 필터 종료========
import javax.servlet.*;
import java.io.IOException;
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("SecondFilter가 생성되었습니다.");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("==========Second 필터 시작==========");
chain.doFilter(request, response);
System.out.println("==========Second 필터 종료==========");
}
@Override
public void destroy() {
System.out.println("SecondFilter가 사라집니다.");
Filter.super.destroy();
}
}
:두 번째 Filter 작성
import book.study.security.FirstFilter;
import book.study.security.SecondFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegister() {
FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
registrationBean.setOrder(1); // 1)
return registrationBean;
}
@Bean
public FilterRegistrationBean<SecondFilter> secondFilterRegister() {
FilterRegistrationBean<SecondFilter> registrationBean = new FilterRegistrationBean<>(new SecondFilter());
registrationBean.setOrder(2); // 2)
return registrationBean;
}
}
:두 번째 Filter인 SecondFilter를 Spring Bean으로 등록
1) registrationBean.setOrder(1) 2) registrationBean.setOrder(2)
:두 개의 Filter가 지정된 순서로 실행되도록 registratioinBean.setOrder() 메서드로 순서 지정할 수 있음
:파라미터로 지정한 숫자가 적은 숫자일수록 먼저 실행됨
애플리케이션 재실행 후 Controller의 핸들러 메서드에 request를 전송하면 아래 같은 결과 출력
========First 필터 시작========
==========Second 필터 시작==========
Hello
==========Second 필터 종료==========
========First 필터 종료========
"Filter는 나머지 Filter와 Servlet에 영향을 주기 때문에 Filter의 실행 순서가 중요함"
핵심
-Spring Boot에서는 FilterRegistrationBean을 이용해 Filter를 등록할 수 있음
-Spring Boot에서 등록하는 Filter는 아래 방법으로 실행 순서 지정 가능
a. Spring Bean으로 등록되는 Filter에 @Order 애너테이션 추가 및 Order 인터페이스를 구현
b. FilterRegistrationBean의 setOrder() 메서드를 이용해 순서 지정 가능