이전에 서블릿 필터와 스프링 인터셉터에의 차이에 대해 따로 정리는 여기에 있다!
질문에 대비해 차이 및 추가적으로 요약 정리를 더 해보자면
스프링 MVC 2편 - 로그인 처리2 - 필터, 인터셉터에서 관련하여 글을 작성하였습니다.
필터와 인터셉터는 관리되는 영역이 다르다. 필터는 스프링 이전의 서블릿 영역에서 관리되지만, 인터셉터는 스프링 영역에서 관리되는 영역이기 때문에
=> 필터는 스프링이 처리해주는 내용들을 적용 받을 수 없다.
=> 🚨 이로 인한 차이로 발생하는 대표적인 예시가 필터는 스프링에 의한 예외처리가 되지 않는다는 것이다.
+) 참고로 일부 포스팅 또는 자료에서 필터(Filter)가 스프링 빈으로 등록되지 못하며, 빈을 주입 받을 수도 없다고 하는데, 이는 잘못된 설명이다.
=> 이는 매우 옛날의 이야기이며🤔 , 필터는 현재 스프링 빈으로 등록이 가능하며, 다른 곳에 주입되거나 다른 빈을 주입받을 수도 있다.
스프링을 사용한다면 ControllerAdvice
와 ExceptionHandler
를 이용한 예외처리 기능을 주로 사용한다.
그래서 예외처리에 관한 예시로 만약 원하는 멤버를 찾지 못하여 로직에서 'MemberNotFoundException'을 던졌다면 404 Status로 응답을 반환하길 원할 것이다.
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MemberNotFoundException.class)
public ResponseEntity<Object> handleMyException(MemberNotFoundException e) {
return ResponseEntity.notFound()
.build();
}
...
}
이처럼 예외처리기를 구현하여 예외가 서블릿까지 전달되지 않고 처리되어야 할 것이다.
-> 그러나 '필터'는 스프링 앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 받을 수 없다.
그래서 만약 필터에서 MemberNotFoundException이 던져졌다면, 에러가 처리되지 않고 서블릿(여기서 말하는 필터 다음 과정인 서블릿은 Dispatcher Servlet을 뜻함)까지 전달된다. 서블릿은 예외가 핸들링 되기를 기대했지만, 예외가 그대로 올라와서 예상치 못한 Exception을 만난 상황이다.
=> 따라서 내부에 문제가 있다고 판단하여 500 Status로 응답을 반환한다.
=> 이를 해결하려면 필터에서 다음과 같이 응답(Response) 객체에 예외 처리가 필요하다.
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse servletResponse = (HttpServletResponse) response;
servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
servletResponse.getWriter().print("Member Not Found");
}
}
필터는 위에도 나오다시피 Filter Chaining(다음 필터 호출) 이라는 기능이 있다. 그리고 이때 Request/Respsonse 객체를 넘겨줄 수 있다.(물론 NPE가 나겠지만서도)
ex) 필터에서는 이런 식으로 넣어줄 수 있다는 것이다.
public MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// 개발자가 다른 request와 response를 넣어줄 수 있음
chain.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse());
}
}
스프링 MVC 2편 - 예외 처리와 오류 페이지
에 관하여
'필터'는 WAS(웹컨테이너)에 의해 관리가 되는 영역이고, '인터셉터'는 DispatcherServlet
(스프링의 프론트컨트롤러) 이후 영역이므로 스프링에 의해 관리되는 영역이다.
공통점
컨트롤러 진입전 실행로직을 작성할 수 있다는 것.
차이점
'필터'는... 스프링이 관리하지 않으므로, Spring Context를 사용할 수 없다는 것.
@ControllerAdvice
로 스프링의 도움을 받아 객체지향적으로 예외처리를 할 수 있다.
¹직접 response
에 접근하여 예외처리를 하거나, 톰캣의 경우 를 선언하여 처리하거나, ²인터셉터까지 계속 통과시켜 인터셉터에게 예외처리를 미뤄버려야 한다.
만약 인터셉터에게 미루지 않고 에러가 발생한 필터에서 doFilter()
를 호출하여 다음필터로 전파하지 않고 바로 return 으로 클라이언트로 response
를 보내게 되면...
=> 프론트 컨트롤러인 'DispatcherServlet'
에 서블릿 자체가 도달하지 않으므로 스프링에서는 알 방법이 없다...😥
그러므로
필터는 DispatcherServlet 외부에 존재하기 때문에 예외가 발생했을 때 ErrorController에서 처리해야 합니다.
인터셉터는 DispatcherServlet 내부에 존재하기 때문에 @ControllerAdvice를 적용해서 처리할 수 있습니다.