Spring Framework Filter 등록

2024. 1. 28. 22:53JAVA/Spring

 

목차

- Filter의 개념

- FilterRegistrationBean을 이용한 Filter 등록

- @Component를 이용한 단순 Filter 등록

- @WebFilter + @ServletComponentScan을 이용한 Filter 등록

- Filter 등록시 주의사항

 

이번글에서는 Spring Framework에 Filter에 대해서 소개합니다. Filter의 간단한 개념과 Spring Framework에 Filter를 등록하는 다양한 방법과 Filter 등록시 주의사항에 대해서 소개합니다.

 

1. Filter의 개념

필터(Filter)는 J2EE(Java 2 Enterprise Edition) 표준 스펙 기능이며, 클라이언트의 요청이 들어오면 Spring Context의 DispatcherServlet에 요청이 들어오기 전후에 WebContext 영역에서 URL 패턴에 맞는 모든 요청에 대한 부가작업을 처리할 수 있는 기능을 제공합니다.

 

Filter를 등록함으로써 클라이언트의 데이터 변환, 사용자 인증, 자원 접근에 대한 로깅등에 사용합니다.

 

2. FilterRegistrationBean을 이용한 Filter 등록

Spring Framework에 Filter를 등록하는 첫번째 방법은 FilterRegistrationBean 스프링 빈을 생성하는 방법입니다. FilterRegistrationBean 스프링 빈을 등록하기 위해서는 @Configuration 애노테이션이 설정된 클래스에 스프링 빈을 등록하면 됩니다.

 

예를 들어 다음과 같은 Cors Filter를 구현합니다.

public class CorsFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
		IOException,
		ServletException {
		HttpServletResponse servletResponse = (HttpServletResponse)response;
		servletResponse.setHeader("Access-Control-Allow-Origin", "*");
		servletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT");
		servletResponse.setHeader("Access-Control-Max-Age", "3600");
		servletResponse.setHeader("Access-Control-Allow-Headers", "*");
		chain.doFilter(request, response);
	}
}

 

위와 같이 구현한 Cors Filter를 등록하기 위해서 스프링 설정 클래스를 구현합니다.

@Configuration
public class FilterConfig {

	@Bean
	public FilterRegistrationBean<CorsFilter> corsFilter(){
		FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>(
			new CorsFilter());
		registrationBean.setUrlPatterns(List.of("/*"));
		return registrationBean;
	}
    ...
 }

FilterRegistrationBean 인스턴스를 생성하고 생성자 매개변수에 필터 인스턴스를 생성하여 전달합니다. 또한 setUrlPatterns 메소드를 호출하여 Filter에 매치되는 URL 패턴을 설정합니다.

 

FilterRegistrationBean 등록 방법의 장단점

- Filter를 등록하는 방법이 매우 간단하고 코드도 간결합니다. 

- FilterRegistrationBean 등록 방법의 단점은 Filter 클래스만 가지고 등록할 수 없고 별도의 스프링 빈 설정 정의가 필요합니다.

 

3. @Component를 이용한 단순 Filter 등록

@Component를 이용한 Filter 등록방법은 Filter 클래스에 @Component를 적용하는 방법입니다.

 

예를 들어 다음과 같이 Filter 클래스를 정의하고 @Component 애노테이션을 적용하여 스프링 빈으로 등록합니다.

@Component
public class CorsFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
		IOException,
		ServletException {
		//...
	}
}

 

@Component를 이용한 단순 Filter 등록 장단점

- Filter 구현 클래스만으로 스프링 빈까지 등록이 가능합니다.

- 단점은 별도의 URL 패턴을 적용할 수 없기 때문에 모든 경로에 대해서 Filter가 적용됩니다.

 

4. @WebFilter + @ServletComponentScan을 이용한 Filter 등록

@WebFilter 및 @ServletComponentScan을 이용한 방법은 @ServletComponentScan을 통해서 해당 애노테이션의 패키지 위치를 기준으로 @WebFilter 애노테이션이 적용된 Filter 클래스를 탐색하고 스프링 빈으로 등록합니다.

 

다음 코드는 Filter 클래스를 정의하고 @WebFilter 애노테이션을 정의합니다.

@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
		IOException,
		ServletException {
		// ...
	}
}
@ServletComponentScan
@SpringBootApplication
public class FilterExample03 implements ApplicationRunner {
	// ...
 }

 

@Webfilter를 이용한 Filter 등록 방법의 장단점

- Filter 클래스를 정의하고 별도의 스프링 빈 설정을 추가하지 않아도 됩니다.

- @Component 등록 방법과는 다르게 URL 패턴도 설정할 수 있습니다.

- @WebFilter는 자바 표준 스펙 기능이기 때문에 스프링 프레임워크에 등록하기 위해서는 별도의 @ServletComponentScan 애노테이션 설정이 필요합니다.

 

5. Filter 등록시 주의사항

Filter 등록시 주의사항은 @Component 등록 방법과 @WebFilter + @ServletComponentScan 등록 방법을 혼용해서 사용하면 안됩니다. 두 방법을 혼용해서 등록시 Filter가 두번 등록되기 때문에 @Component로 등록된 Filter는 개발자의 의도하는 다르게 모든 URL 패턴에 매칭되어 실행되어 버립니다.

 

예를 들어 다음과 같이 Filter 클래스를 구현하고 @Component와 @WebFilter를 동시에 등록합니다.

@Component
@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
		IOException,
		ServletException {
		//...
	}
}
 
@ServletComponentScan
@SpringBootApplication
public class FilterExample04 implements ApplicationRunner {
	// ...
}

 

위와 같이 두 등록 방법을 혼용해서 사용하게 되면 CorsFilter 타입으로 2개의 스프링 빈이 생성됩니다. 즉, 스프링 컨테이너에는 서로 다른 CorsFilter 스프링 빈이 저장되는 것입니다. 위와 같이 혼용해서 사용되어 스프링 빈이 2개가 등록되는 경우 문제점은 @Component 애노테이션을 적용하여 등록된 스프링 빈은 모든 URL 패턴에 매칭되어 실행되는 문제가 발생합니다. 이는 개발자의 의도하는 다르게 동작할 가능성이 높습니다.

 

정리

Filter는 WebContext 영역 안에서 클라이언트의 요청을 대상으로 URL 패턴에 맞는 요청에 대하여 부가적인 기능을 수행하는 역할입니다. Filter를 스프링 프레임워크에 등록하는 방법으로는 FilterRegistrationBean 타입의 스프링 빈으로 등록하는 방법, @Component를 이용하여 모든 URL 패턴에 매칭되는 단순 Filter를 등록하는 방법, @WebFilter를 이용하여 Filter 클래스 구현 및 설정까지 하나의 클래스에서 등록하는 방법이 있습니다. 또한 마지막으로 @Component와 @WebFilter를 혼용해서 사용하게 되는 경우 서로 다른 Filter 스프링 빈이 등록되어 @Component로 등록된 스프링 빈은 개발자의 의도와는 다르게 Filter가 수행될 수 있습니다.

 

References

source code : https://github.com/yonghwankim-dev/spring/tree/main/spring-demo/src/main/java/nemo/filter/registration
https://devhj.tistory.com/59
https://dev-coco.tistory.com/173