본문 바로가기
스터디/Spring

필터와 인터셉터

by Big Sun 2023. 4. 7.
728x90

애플리케이션의 여러 로직에 공통으로 관심이 있는 것들을 공통 관심사라고 한다.

공통 관심사 중 웹과 관련된 것들을 처리할 때는 HTTP의 헤더나 URL의 정보들이 필요한데, 이를 처리하는 방법들을 서블릿 필터나 스프링 인터셉터가 제공한다.

필터


필터는 J2EE 표준 스펙 기능으로 디스패처 서블릿에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공한다.

 

참고로, 디스패처 서블릿은 프론트 컨트롤러 (스프링의 가장 앞단에 존재하는 것)이므로, 필터는 스프링 범위 밖에서 처리가 된다.

즉, 필터는 스프링 컨테이너가 아닌 톰켓과 같은 서블릿 컨테이너에서 관리가 되는 것이다.

(하지만, 스프링 빈 등록은 가능하다!)

 

필터 흐름은 아래와 같다.

 

HTTP 요청 → WAS → 필터 → 서블릿 → 컨틀롤러

 

 

필터를 적용하면, 필터가 호출 된 다음에 서블릿이 호출된다.

 

따라서, 모든 요청에 대한 로깅, 보안 관련 공통 작업, 이미지/데이터 압축 및 문자열 인코딩, Spring과 분리되어야 하는 기능등에 사용된다.

 

필터는 아래의 3가지 메소드를 가지고 있다.

 

  1. init 메소드 : 필터 객체 초기화, 처음에만 init 메서드를 호출하고 이후에는 doFilter만 호출한다.
  2. doFilter 메소드
  3. destory 메소드 : 필터 객체 제거 및 자원 반환, 마지막에만 호출되며, 이후에는 doFilter를 호출하지 않는다.

 

예를 들어, 로그 필터를 구현한다면 아래와 같다.

 

로그 필터 구현


@Slf4j
public class LogFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
				log.info("log filter init");
		}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
	FilterChain filterChain) throws IOException, ServletException {

        //다운 캐스팅
        HttpServletRequest httpRequest = (HttpServletRequest) request; 
        String requestURI = httpRequest.getRequestURI();

        String uuid = UUID.randomUUID().toString();

        try {
            log.info("REQUEST [{}][{}]",uuid,requestURI);
            chain.doFilter(request,response);
        }catch(Exception e){
            throw e;
        } finally {
            log.info("RESPONSE [{}][{}]",uuid, requestURI);
        }

    }

    @Override
    public void destroy() {
		log.info("log filter destroy");
    }
    
}

 

chain.doFilter(request, response);

  • 이 다음 필터가 있다면, 필터를 호출하고 필터가 없으면 서블릿을 호출한다.
  • 만약, 이 로직을 호출하지 않으면 다음 단계로 진행되지 않는다.

 

필터 등록


@Configuration
public class WebConfig {

        @Bean
        public FilterRegistrationBean logFilter() {

            FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
            filterRegistrationBean.setFilter(new LogFilter());
            filterRegistrationBean.setOrder(1);
            filterRegistrationBean.addUrlPatterns("/*");
            return filterRegistrationBean;
            
    	} 
        
}

 

FilterRegistrationBean을 사용해서 등록하면 된다.

  • setFilter → 등록할 필터를 지정
  • setOrder → 필터는 체인으로 동작하는 데, 동작하는 순서를 지정한다.
  • addUrlPatterns → 필터를 적용할 URL 패턴을 지정한다.

 

필터는 공통된 보안 및 인증/인가 작업, 모든 요청에 대한 로깅, 이미지/데이터 압축 및 문자열 인코딩등에 사용되 수 있다.

 

스프링 인터셉터


스프링 인터셉터도 서블릿 필터와 같이 웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기술이다.

이는 스프링 MVC가 제공하는 기술으로, 서블릿 필터와 비슷하게 웹과 관련된 공통사항을 처리하지만 더 정교하다.

 

구체적으로, 디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.

인터셉터는 필터와 달리 스프링 컨텍스트에서 동작을 한다.

 

스프링 인터셉터 흐름은 아래와 같다.

 

HTTP 요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터 → 컨트롤러

 

위 그림처럼 스프링 인터셉터는 총 3번 각기 다른 상황에 사용할 수 있다.

 

preHandle(컨트롤러 호출 전)

  • preHandle의 응답값이 true이면 다음으로 진행하고, 만약 false이면 더는 진행하지 못 한다.(진행이 끝난다는 의미)

postHandle(컨틀로러 호출 후)

  • 만약, 컨트롤러에서 예외가 발생하면, postHandle은 호출되지 않는다. 
  • ModelAndView 타입의 정보를 사용할 수 있다.

afterCompletion(요청 완료 이후)

  • 뷰가 렌더링 된 이후에 호출된다. → 파라미터로 ModelAndView를 가지고 있다.
  • 예외가 발생하더라고 항상 호출된다. → 예외가 왜 발생했는 지를 로그로 알 수 있다.

 

스프링 인터셉터 인터페이스


public interface HandlerIntercepter {

	default boolean preHandle(HttpServletRequest request, HttpServletResponse
  response, Object handler) throws Exception {}

	default void postHandle(HttpServletRequest request, HttpServletResponse
  response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}

	default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
  Object handler, @Nullable Exception ex) throws Exception {}
	
}

 

인터셉터 등록


@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**","/*.ico","/error")
		}

}
  • registry.addInterceptor() : 인터셉터를 등록한다.
  • order() : 인터셉터의 호출 순서를 지정한다.
  • addPathPatterns() : 인터셉터를 적용할 URL 패턴을 지정한다.
  • excludePathPatterns() : 인터셉터에서 제외할 패턴을 지정한다.

 

WebMvcConfigurer을 구현한 클래스에서 IntercepterRegistry에 등록한 순서대로 인터셉터가 동작한다.

 

 

인터셉터는 세부적인 인증/인가 등과 같은 공통 작업, API에 대한 로깅, Controller로 넘겨주는 데이터 가공 등에 사용될 수 있다.

 

 

정리하자면, 아래와 같다.

 

서블릿 필터 vs 스프링 인터셉터

 

  • 웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기술
  • 스프링 인터셉터는 서블릿 필터에 비해 더 세밀하고, 다양한 기능을 지원한다.
    • 예를 들어서, 서플릿 필터의 경우 단순하게 doFilter()만 제공하지만 인터셉터는 컨트롤러 호출 전,호출 후,그리고 요청 완료 이후와 같이 단계적으로 더 세밀하다.
    • 또한, 서블릿 필터의 경우 매개변수로 request,response만 제공하였지만 인터셉터는 어떤 컨트롤러가 호출되는 지 호출 정보도 받을 수 있다.
    • 마지막으로, 어떤 modelAndView가 반환되는 지 응답 정보도 받을 수 있다.
  • 필터는 관리되는 컨테이너가 서블릿 컨테이너이고, 인터셉터는 스프링 컨테이너이다.
  • 필터의 경우 스프링으로 예외 처리를 할 수 없어 try~catch문을 사용해야하고, 인터셉터의 경우 스프링으로 예외처리가 가능하다.

 

 

감사합니다!!

 

  •  

 

인프런의 김영한님의 강의를 듣고 정리한 포스팅입니다.

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com

 

728x90