[영상후기] [10분 테코톡] 조시, 쿤의 서블릿 필터 & 스프링 인터셉터

박철현·2023년 11월 2일
0

영상후기

목록 보기
139/160

movie

  • 공통 관심사항에 대한 처리 : 로그인이 필요하다면 매번 검사해야함
    • Filter나 Interceptor를 활용하여 공통 사항 분리할 수 있음

Servlet Filter

  • Dispatcher Servlet에 요청이 전달되기 전, 후에 부가작업을 처리하는 객체
    • 요청 : 서블릿 도착 전 필터 동작
    • 응답을 할땐 서블릿 동작 후 필터 동작
  • init, destroy 메서드는 기본(선택적 오버라이딩)
  • doFilter 메소드는 반드시 오버라이딩 해줘야 함

서블릿 필터가 제공하는 Init 메서드

  • 생성될 때 한번만 호출
    @Override
    init(final FilterConfig filterConfig) throws ServeletException {
    log.info("LoginFiler.init");
    }
    • FilterConfig : 필터 정보를 담고 있는 객체
    • 톰캣 호출 -> 커넥션 풀 열리고 -> 로그인 필터 init메서드 호출 확인

서블릿 필터가 제공하는 doFilter 메서드

  • 관심 사항 로직들이 담김
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) {
log.info("LoginFilter.doFiler");
HttpServletRequest servletRequest = (HttpServletRequest) request;
try {
	validateToken(servletRequest);
    chain.doFiler(request, response);
} catch(Exception e) {
	HttpServletResponse servletResponse = (HttpServletResponse) response;
    servletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
  }
}
  • FilterChain : filter가 여러개 모여 형성된 체인
    • chain.doFilter(request, response); 메서드를 통해 명시적으로 다음 필터를 동작하도록 해줘야 함
    • doFilter 메서드는 요청이 올때마다 실행되기에 인증 등의 작업 수행하기에 좋음
public interface FilterChain {
	public void doFiler(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}

서블릿 필터가 제공하는 destroy 메서드

  • 소멸이 될 때 한번만 호출
    @Override
    public void destroy() {
    	log.info("LoginFilter.destroy");
    }
  • WAS가 닫히기 전 desroy 호출되고 커넥션 풀이 닫힘

서블릿 필터 등록하는 방법 - @Component

  • Spring Bean 등록하듯이 @Component 이용
    • 모든 URL에 적용됨
    • 특정 URL에만 적용시킬라면 좋진 않은 방법일 듯
    @Slf4j
    @Component
    pulbic class LoginFilter implements Filter {

서블릿 필터 등록하는 방법 - @WebFilter + @ServletComponentScan

  • @Component와 다르게 URL 분리할 수 있음
  • @ServletComponentScan를 꼭 붙여줘야 함
    • ComponentScan과 같이 Bean을 등록하는 것
    • 대상이 WebFilter나 WebServlet, WebListener 서블릿 객체들을 Servlet Container 위에 올려주는 어노테이션
    • Spring Container가 아닌 Servelet Container에 등록되기 때문에 @Order(1) 적용이 안됨
    • 따로 순서를 지정해주는 어노테이션이 없음
 @Slf4j
 @WebFilter(urlPatterns = "/users/me/*")
 public class LoginFilter implements Filter {
  @SpringBootApplication
  @ServletComponentScan
  public class Application {
  	public static void main(String[] args) {
   	SpringApplication.run(Application.class, args);
   }
  }

서블릿 필터 등록하는 방법 - FlterRegistrationBean으로 등록

@Bean
public FilterRegistrationBean addFilter() {
	FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.serFilter(new LoginFilter(jwtTokenProvider));
    filterRegistrationBean.setOrder(1);
    filterRegistrationBean.addUrlPatterns("/users/me/*");
    return filterRegistrationBean;
}
  • 순서와 Url 지정하고 싶으면 위 방법을 이용

서블릿 필터의 동작방식

  • ApplicationFilterChain이 구현체
    • 실제 doFilter 호출 시 ApplicationFilterChain이 동작
    • Mocking을 해서 FilterChain시에는 MockFilterChain이 돌아감
  • FilterChain의 doFilter 실행
    1. pos가 0인 Filter의 doFilter 실행 -> chain.doFilter 호출
    2. pos가 1인 Filter의 doFilter 실행 -> chain.doFilter 호출
    3. ...
      ...
      필터의 개수만큼 반복하며 doFilter 호출로 다음 필터를 호출함(doFilter를 무조건 호출해야 함)
  • 모든 필터가 동작하면 DispatcherServlet으로 이동함

인터셉터

  • 스프링이 제공하는 기술로, 디스패처 서블릿이 컨트롤러를 호출하기 전/후 요청에 대해 부가적인 작업을 처리하는 객체
  • 스프링 인터셉터 인터페이스에서 제공하는 메서드(default 메서드로 필요한것 선택하여 사용할 수 있음)
    • preHandle : 핸들러 실행 전 동작하는 메서드
      • 비즈니스 로직에서 공통 로직
    • postHandle : Handler 이후 실행 메서드
      • 파라미터로 ModelAndView가 있음
      • ModelAndView에 대해 추가적 작업 하고싶을 경우 사용
    • afterCompletion : Handler 이후 실행 메서드
      • 파라미터로 Exception이 있음
        • 비즈니스 로직에서 예외 발생 시 처리 가능
      • 리소스를 정리할때도 사용할 수 있음

인터셉터 등록 방법

@Configuration
public class WebConfig implements WebMvcConfugurer {
	private final LoginInterceptor loginInterceptor;
    
    public WebConfig(LoginInterceptor loginInterceptor) {
    	this.loginInterceptor = loginInterceptor;
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(loginInterceptor)
    		.addPathPatterns("/**")
            .excludePathPatterns("/signup", "/login");
    }
}
  • WebMvcConfigurer 인터페이스를 구현한 클래스 내부에서 addInterceptors 라는 메서드를 오버라이드해서 추가할 수 있음
    • 인터셉터 등록, 적용할 URI 요청, 적용하지 않을 URI 요청 등록

스프링 인터셉터 - 호출 시점

  • 핸들러 조회 -> 알맞은 핸들러 어댑터 가져옴 -> preHandle -> 핸들러 어댑터를 통해 핸들러 실행 -> postHandle -> view관련 처리 -> afterCompletion

스프링 인터셉터 동작방식

  • Handler 매핑
  • Interceptor preHandle 반복문으로 수행
    • 오름차순 순번
  • Handler Adapter에 의해 Handler 호출
  • PostHandle 반복문으로 수행
    • 인터셉터 역순으로 수행
  • view 관련 로직 처리
  • afterCompletion 동작

필터와 인터셉터 차이

필터인터셉터
자바 표준 스펙스프링이 제공하는 기술
다음 필터 실행을 위해 개발자가 명시적 작성 (doFilter)다음 인터셉터 실행을 위해 개발자가 신경써야 하는 부분이 없다
ServletRequest, ServletResponse를 필터 체이닝 중간에 새로운 객체로 바꿀 수 있다.ServletRequest, ServletResponse를 인터셉터 체이닝 중간에 새로운 객체로 바꿀 수 없다.
필터에서 예외가 발생하면 @ControllerAdvice에서 처리하지 못한다.인터셉터에서 예외가 발생하면 @ControllerAdvice에서 처리가 가능하다.
  • @ControllerAdvice의 적용 범위는 dispatcherServlet 내부 동작
    • 인터셉터 자체가 DispatcherServlet에서 호출되기에 ControllerAdvice 가능
    • 필터의 경우 DispatcherServlet 이전 또는 종료 이후에 호출되기에 불가

필터와 인터셉터 언제 사용해야 할까?

  • Spring에서 제공하는 기본 Filter들의 공통점 : 전문적 Web 관련 로직

    • 인코딩
    • HTTP Method(Get, POST, PUT, Patch, DELETE) Mapping
  • Interceptor : ModelAttribute binding 속성들을 Request에 넣어주거나 Spring 관련 작업

  • 관심사의 분리로 생각하면 좋을 듯

    • 좀 더 큰범위(Web)이면 필터
    • 세세한 인가처리, 스프링에 관련된 기술은 인터셉터면 좋을듯
  • 기준을 잘 정하는게 좋음!

profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글

관련 채용 정보