꼬물꼬물

필터(Filter)와 인터셉터(Interceptor) 본문

코딩/CS

필터(Filter)와 인터셉터(Interceptor)

멩주 2022. 11. 1. 17:24

Filter와 Interceptor

  • 스프링에서 요청이 Controller Layer로 들어오기 전 처리해야하는 작업
    • 인증, 인가, XSS 방어, 데이터 압축, 인코딩
  • 이러한 작업은 모든 컨트롤러 메서드에서 실행하는 것이 아닌 공통적으로 처리하는 것이 효율적이다.
    • AOP(Aspect Oriented Programming): 관점 지향 프로그래밍
      • 공통 관심사항과 핵심 관심사항으로 분리

# Filter

  • 서블릿 필터는 요청이 서블릿으로 전송되기 전에 요청을 가로채고 처리하는데 사용할 수 있다.
  • 또한, 서블릿이 완료되고 컨테이너가 다시 클라이언트에게 응답시, 작업을 처리할 수 있다.
    • 인증 필터
    • 응답 데이터 압축
  • 가장 앞단에 존재하는 포스트 컨트롤러인 디스패처 서블릿 요청 전,후에 부가적인 작업을 처리할 수 있는 기능을 제공한다.
  • doFilter 메서드에서 필터링을 수행

✔️ 서블릿 필터 인터페이스(implements Filter)의 수명주기

public class Service implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

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

    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
  1. init()
    • 호출 시기: 컨테이너가 필터를 초기화할 때
    • 필터 수명 주기에 한 번만 호출되며, 해당 메서드의 모든 리소스를 초기화해야 한다.
    • FilterConfig는 컨테이너에서 초기화 매개변수와 서블릿 컨텍스트 개체를 제공한다.
  2. doFilter()
    • 자원에 필터를 적용해야 할 때, 컨테이너가 매번 호출한다.
    • 컨테이너는 필터에 대한 요청 및 으압 개체 함조를 제공한다.
    • FilterChain은 다음 필터를 사용하는데 호출
  3. destroy()
    • 컨테이너가 Filter 인스턴스를 삭제하기 전 메서드를 호출한다.
    • 필터에 의해 열린 모든 리소스를 반환한다.
    • 한 번만 호출된다.

1. FilterRegistrationBean 사용하기

Controller.java

@Slf4j
@RestController
@RequestMapping("/api")
public class controller {

    @GetMapping("/test")
    public String test(){
        log.info("call test method");
        return "test";
    }

    @GetMapping("/filter/test")
    public String filterTest(){
        log.info("call filterTest method");
        return "filter Test";
    }
}

Application.java

@SpringBootApplication
public class TodayApplication {

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

   @Bean
   public FilterRegistrationBean setFilterRegistration(){
      FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
      filterRegistrationBean.addUrlPatterns("/api/filter/*"); // /api/filter로 들어오는 경우 Myfilter 실행
      return filterRegistrationBean;
   }
}

MyFilter.java

@Slf4j
public class MyFilter implements Filter {

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

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
				 log.info("doFilter MyFilter, uri : {}", ((HttpServletRequest)request).getRequestURL());
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
				 log.info("destroy MyFilter");
        Filter.super.destroy();
    }
}
  • 어플리케이션 실행

  • localhost:8080/api/filter/test
    • filter가 실행되고 그 다음 controller의 메서드가 실행된다.

  • 종료

 

2. @WebFilter + @ServletComponentScan 사용하기

  • @ServletComponentScan 어노테이션을 @Configuration 어노테이션이 설정된 곳에 걸어주기
  • 필터에 @WebFilter 어노테이션 사용

Application.java

@ServletComponentScan
@SpringBootApplication
public class TodayApplication {

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

MyFilterAnnotation.java

@Slf4j
@WebFilter(urlPatterns = {"/api/filter/*"})
public class MyFilterAnnotation implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
				 log.info("init MyFilterAnnotation");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
				 log.info("doFilter MyFilterAnnotation, uri : {}", ((HttpServletRequest)request).getRequestURL());
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
				 log.info("destroy MyFilterAnnotation");
        Filter.super.destroy();
    }
}
  • 어플리케이션 실행

  • localhost:8080/api/filter/test

  • 종료

[참고]

 

# 인터셉터(Interceptor)

  • 스프링이 제공하는 기술로 디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청을 가로채 응답을 참조하거나 가공할 수 있게 도와준다.

  • 인터셉터는 필터와 다르게 스프링 컨텍스트 내부에서 동작한다.
  • 디스패처 서블릿(Dispatcher Servlet)은 내부적으로 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청한다.
  • 그 결과로 실행 체인(HandlerExecutionChain)을 반환한다.
  • 실행 체인은 스프링 컨테이너에 인터셉터가 등록되어 있다면 인터셉터들을 순차적으로 거친 후 컨트롤러를 실행하도록 한다.

인터셉터의 실행주기

public interface HandlerInterceptor {

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

		return true;
	}

	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 {
	}

}
  1. preHandle()
    • 컨트롤러가 호출되기 전에 실행된다.
    • 요청 데이터 전처리, 가공 등에 사용
  2. postHandle()
    • 컨트롤러가 호출된 후에 실행된다.
    • 후처리 작업이 있을 때 사용
  3. afterCompletion()
    • 뷰 생성을 포함한 모든 작업이 완료 된 후에 실행된다.

 

[정리]

  • 필터는 Java가 지원, 인터셉터는 Spring이 지원하는 기능이다.
  • 필터는 Dispatcher Servlet보다 앞에서 동작
  • 인터셉터는 필터랑 달리 컨트롤러가 동작한 후에 작업을 처리한다.

 

[참고]

'코딩 > CS' 카테고리의 다른 글

기초 정렬 알고리즘  (0) 2022.11.07
페이지 교체 알고리즘  (0) 2022.11.01
CPU 작동 원리  (0) 2022.09.20
JDBC, SQL Mapper, ORM  (0) 2022.09.05
Day2 질문  (0) 2022.04.25