서블릿 컨테이너에서 서블릿에 요청이 도달하기 전에 요청을 필터링 작업을 수행하려는 경우 사용된다. 필터는 Filter 인터페이스를 상속받아 구현할 수 있다.
class FirstFilter : Filter {
private val logger = LogManager.getLogger(FirstFilter::class.java)
override fun init(filtercCongig: FilterConfig){
logger.info("First Filter Init")
}
override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
logger.info("First Filter")
chain?.doFilter(request, response)
}
override fun destroy() {
logger.info("First Filter Destroy")
}
}
Filter 인터페이스를 구현하기 위해서는 필수로 doFilter()를 구현해야하고 필요에 따라 init()과 destroy()를 구현해 필터 서블릿의 생명 주기를 다룰 수 있다.
필터는 필터 체인 방식으로 작동하는데 chain.doFilter(req, res)가 없으면 다음 필터로 넘어갈 수 없다. 이는 필터를 거친 후 작동하는 디스패처 서블릿의 작동도 불가하고 서버가 멈춰버린다는 뜻이다. 따라서 필터를 사용할떄 chain.doFilter()를 잊어서는 안된다.
스프링부트에서는 두가지 방식으로 필터를 등록할 수 있다.
필터를 등록한다는 것은 필터 클래스를 스프링 빈으로 등록한다는 것이다. 따라서 @Configuration
어노테이션으로 빈을 등록하는 설정 클래스를 만들어야 하고 WebMvcConfigurer
인터페이스를 구현해야한다.
@Configuration
class FilterConfiguration : WebMvcConfigurer {
@Bean
fun firstFilterRegistrationBean(): FilterRegistrationBean<FirstFilter> {
val registrationBean = FilterRegistrationBean(FirstFilter())
registrationBean.order = 0
registrationBean.urlPatterns = mutableListOf("/*")
return registrationBean
}
@Bean
fun secondFilterRegistrationBean(): FilterRegistrationBean<ThirdFilter>{
val registrationBean = FilterRegistrationBean(ThirdFilter())
registrationBean.order = 2
registrationBean.urlPatterns = mutableListOf("/*")
return registrationBean
}
}
필터를 등록하는 빈은 FilterRegistrationBean<Filter>
인스턴스를 반환한다. FilterRegistrationBean 인스턴스의 여러 필드(order, urlPatterns 등)을 설정해 필터의 순서나 적용될 요청 uri 패턴등을 지정할 수 있다.
필터 클래스에 @WebFilter(urlPatterns = "")를 적용해주면 간단하게 필터가 등록된다.
@WebFilter(urlPatterns = ["/*"])
class SecondFilter : Filter{
private val logger = LogManager.getLogger(SecondFilter::class.java)
override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
logger.info("Second Filter")
chain?.doFilter(request, response)
}
}
주의점
@WebFilter 어노테이션을 필터를 등록할 경우 필터 순서와 같은 세부 설정은 불가능하다. @Order 어노테이션으로 순서를 지정할 수 있다고 하는 포스트를 보긴했는데 내 환경에서는 적용되지 않았다. 따라서 순서에 관계 없이 수행되어도 되는 필터에 이 방법을 사용하고 순서 설정과 같은 세부 설정이 필요할 경우 직접 필터 빈을 등록하는 것이 좋을것 같다.