본문 바로가기
Java & Spring Boot

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

by 향각산 2022. 10. 4.

필터는 서블릿 기능, 인터셉터는 스프링 기능이다.

 

애플리케이션에서 공통으로 관심이 있는 관심사를 공통 관심사(cross-cutting concern)이라고 한다.

공통관심사는 AOP나 서블릿 필터, 스프링 인터셉터 등 다양한 방법으로 해결할 수 있다.

ex) 모든 메서드의 동작 시간, 가장 많이 호출되는 메서드 저장

그 중 웹과 관련된 공통 관심사는 필터나 인터셉터로 해결하는것이 좋다. (ex 로그인 여부 체크)

 

필터 흐름

[HTTP 요청 -> 웹서버 -> 필터 -> 서블릿 -> 컨트롤러]

필터를 적용하면 필터가 호출 된 다음에 서블릿(디스패처 서블릿) 호출

 

필터 체인

[HTTP 요청 -> 웹서버 -> 필터1 -> 필터2 ... -> 서블릿 -> 컨트롤러]

필터를 여러개로 구성 가능

 

필터 인터페이스 기본 사용법 - Servlet init, service, destroy 생각하면 된다.

init() : 필터 초기화 메서드, 서블릿 컨테이너 등록 시 호출

doFilter(): 고객의 요청마다 호출되는 메서드

destroy(): 필터 종료 메서드, 컨테이너 종료 시 호출

 

사용하려면 다음과 같이 작성하면 된다.

특징은 스프링 mvc전에 동작하기 때문에 ServletRequest, ServletResponse가 사용되고,

chain.doFilter()를 꼭 호출해줘야 함 (안할경우 멈춘다.)

import javax.servlet.*;
import java.io.IOException;

public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        chain.doFilter(request, response);
    }
}

Spring boot에서 필터를 bean에 등록하는 법은 다음과 같다.

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean testFilter() {
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new TestFilter());
        filterFilterRegistrationBean.setOrder(1);
        filterFilterRegistrationBean.addUrlPatterns("/*");
        return filterFilterRegistrationBean;
    }

}

 

 

 

스프링 인터셉터

필터와 적용되는 순서와 범위, 사용방법이 다르다. 필터와 비슷한 용도로 사용되며 스프링이 지원하기 때문에 필터보다 좀 더 많은 기능들을 제공한다. 필터와 인터셉터를 사용할 일이 있다면 인터셉터를 쓰는것을 추천한다. 이유는 스프링 지원으로 얻을수 있는 정보와 편리한 기능이 많기 때문이다.

 

인터셉터 흐름

[HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러]

 

인터셉터 체인

[HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터1 -> 인터셉터2 ... -> 컨트롤러]

 

스프링 인터셉터 기본 사용법

preHandle : 컨트롤러 호출 전

postHandle : 컨트롤러 호출 후

afterCompletion : http 요청이 끝날때, 뷰 렌더링 이후로 호출됨

 

사용하려면 다음과 같이 작성하면 된다.

preHandle을 false로 리턴하면 컨트롤러 호출하기전에 끝난다.

만약 컨트롤러에서 Exception이 발생하면 postHandle이 동작하지 않는다. 

컨트롤러 이후에 실행할 코드가 있다면 afterCompletion에 작성하도록 하자.

public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

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

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

Spring boot에서 인터셉터를 빈으로 등록하는법

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

WebMvcConfigurer을 상속받고 addInterceptors를 오버라이딩 해야한다.

주의할점은 필터에서 사용한 addUrlPatterns랑 addPathPatterns랑 들어가는 규칙이 다르다. (같은 /* 을 작성해도 의미가 다르다.)

그 외에 excludePathPatterns같은 추가적인 기능도 존재한다.

addInterceptors가 void여서 추가하려면 메서드를 추가로 작성하지않고 그 안에 addInterceptor를 하나 더 작성하면 된다.

 

출처 : 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 (김영한) 내용 중 일부를 정리함.