티스토리 뷰

Spring-boot

[Spring boot] Filter 설정

개발자-김씨 2021. 4. 28. 17:03
반응형

spring boot 학습 & 세팅 3탄 (2.3.9 RELEASE  docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/html/)

 

1. @Component  또는 @ServletComponentScan WebFilter)

임베디드 WAS의 경우, 자동 설정에 의해서 Filter를 구현할 클래스에 @Component만 붙여줘도 필터가 등록된다.

@Component
public class FirstFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    					FilterChain chain) throws IOException, ServletException {
    .....
    
}

ServletContextInitializerBeans : Mapping filters: characterEncodingFilter urls=[/*] order=-2147483648, 
formContentFilter urls=[/*] order=-9900, 
requestContextFilter urls=[/*] order=-105, 
firstFilter urls=[/*] order=2147483647

로그를 확인해보면 자동 설정에 의해 디폴트 필터가 3개 등록되었고 추가한 FirstFilter가 마지막으로(urls=[/*] , order=2147483647) 붙었다.

characterEncodingFilter가 Ordered.HIGHEST_PRECEDENCE로 등록되기 때문에 해당값은 피해서 필터 순서를 지정해야 한다.
다른 필터도 마찬가지..

 

그런데 필터 순서를 지정하지 않았기 때문에 제일 마지막 필터(2147483647)로 등록된다. 필터를 2개 이상 등록해야 한다면 순서를 주기 위해서 @Order 또는 Ordered인터페이스를 구현해야 한다.

@Component
@Order(1)
public class FirstFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    					FilterChain chain) throws IOException, ServletException {
    .....
    
}

 

ServletContextInitializerBeans :Mapping filters: ...firstFilter urls=[/*] order=1, secondFilter urls=[/*] order=2 

로그를 보면 @Order순서에 따라 필터가 잘 등록된 걸 확인할 수 있다.

그런데 @Component로 필터를 등록하면 url패턴을 지정할 수 없기 때문에 기본적으로 모든 url패턴에 매핑된다

@WebFilter 어노테이션을 이용하여 특정 url패턴에 매핑되는 필터를 추가해 보자.

@Component
@Order(2)
@WebFilter(urlPatterns= "/user/*")
public class SecondFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    					FilterChain chain) throws IOException, ServletException {
    .....
    
}

그런데 로그를 보면 secondFilter urls=[/*] order=2 urls이 그대로이다.

@Component로 스캔되서 필터가 등록되었기 때문에 @WebFilter어노테이션이 먹히지 않는다

 

@ServletComponentScan

spring-boot 내장 웹서버를 사용할 경우 서블릿 Component(@WebFilter,@WebServlet, @WebListener)를 스캔할 때 사용하는 어노테이션이다.

Enables scanning for Servlet components (filters, servlets, and listeners). Scanning is only performed when using an embedded web server.
@SpringBootApplication
@ServletComponentScan
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}

@ServletComponentScan붙여주고 다시 실행해보면 /user/*에 매핑된 걸 확인할 수 있다.

Mapping filters: .... 
SecondFilter urls=[/user/*] order=2147483647, 

...


secondFilter urls=[/*] order=1

그런데 @ServletComponentScan + @WebFilter로 한 번 등록되고, 또 @Component로 인해 Filter가 또 스캔되면서 필터가 중복해서 등록된다. 따라서 한 번만 등록되도록 @ServletComponentScan + @WebFilter 방식 또는  @Component방식 중에 하나만 적용되도록 해야 한다.

그런데 @WebFilter로 등록하면(SecondFilter urls=[/user/*] order=2147483647) @Order가 안먹히는걸 확인 할 수 있다. (이 경우 필터 ordering은 스캔 순서대로 지정된다.)

 

정리해보면

1. @Component 방식은 @Order로 순서는 지정할 수 있으나 url패턴 매핑이 불가 

2. @ServletComponentScan + @WebFilter 방식은 url매핑은 가능하나 순서 지정 불가 

 

 

2. FilterRegistrationBean

만약 조금더 세밀한 제어나 Filter클래스를 수정하지 못하는 경우 FilterRegistrationBean을 이용하여 필터를 등록할 수 있습니다.  위에서 정리한 방식에 비해 config 클래스를 별도로 만들어야 하지만 @ServletComponentScan어노테이션이나 필터클래스에 적용한 어노테이션이 필요없습니다.

public class FirstFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    					FilterChain chain) throws IOException, ServletException {
    .....
    
}
@Configuration
public class ServletConfig {

    @Bean
    public FilterRegistrationBean<SecondFilter> secondFilter(){
        FilterRegistrationBean<SecondFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new SecondFilter());
        registrationBean.addUrlPatterns("/user/*");
        registrationBean.setOrder(2);
        registrationBean.setName("second-filter");
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<FirstFilter> firstFilter(){
        FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new FirstFilter());
        registrationBean.addUrlPatterns("/user/*");
        registrationBean.setOrder(1);
        registrationBean.setName("first-filter");
        return registrationBean;
    }
}

setOrder메소드로 순서 설정도 가능하고 addUrlPatthers로 url패턴도 설정 가능하다.

로그를 보면 잘 적용된 걸 확인할 수 있습니다.

Mapping filters: ...
first-filter urls=[/user/*] order=1, 
second-filter urls=[/user/*] order=2, 
characterEncodingFilter urls=[/*] order=-2147483648, 
formContentFilter urls=[/*] order=-9900, 
requestContextFilter urls=[/*] order=-105

 

 

개인적인 생각

필터 설정이 비교적 간단할 경우에는 @Component나  @WebFilter방식으로 설정해도 무관하나 필터 설정이 조금 복잡하거나 필터가 계속 추가될 여지가 많다면 FilterRegistrationBean를 이용하는 방식이 나을거 같다.

 

 

참고

docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/htmlsingle/ ....

www.baeldung.com/spring-servletcomponentscan ..

www.baeldung.com/spring-boot-add-filter ..

docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/servlet/ServletComponentScan.html ...

 

반응형

'Spring-boot' 카테고리의 다른 글

[Spring boot]Redis - Lettuce 설정  (5) 2021.05.06
[Spring boot] 초기화 코드  (0) 2021.04.28
[Spring boot]yml configuration  (0) 2021.04.27
[Spring boot] undertow  (0) 2021.04.23
댓글