서블릿, 필터, 그리고 인터셉터

SeungHoon·2025년 3월 30일

Spring

목록 보기
10/15
post-thumbnail

1. Servlet?

  • Servlet은 Java로 작성된 웹 서버용 프로그램이다.
  • HTTP 요청을 받아서 처리하고, 응답을 만드는 역할을 한다.
  • 웹에서 동적인 페이지를 만드는 역할을 한다.
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String name = request.getParameter("name"); // name 에 해당하는 값을 가져옴 "?name=value 에서 value
        request.setAttribute("name", name); // JSP에 전달할 데이터

        RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/hello.jsp");
        dispatcher.forward(request, response); // JSP로 포워딩
    }
}
  • Servlet을 구현하기 위해서는 HttpServlet을 상속받아야 한다.
  • HTTP 메서드마다 할 행동들을 모두 정의해야줘야 한다. (doGet, doPost ... ) => 꽤나 복잡하고 개발자가 설정해야 될 것들이 많다.
  • 여담으로 위 코드에서 RequestDispatcher 은 인터페이스에 해당하는데 구현체는 Tomcat에서 알아서 주입해준다고 한다. (org.apache.catalina.core.ApplicationDispatcher 을 주입해준다)

2. Servlet Container

  • Servlet의 생명주기를 담당하고 요청을 받아서 적절한 Servlet을 호출하고 답을 반환하는 역할을 한다.
  • 흔히 Tomcat이 Servlet Container 역할을 한다고 보면 된다.
    • Tomcat은 WAS이다. 다만, 경량 WAS, 또는 서블릿 컨테이너 기반 WAS라고 표현하면 더 정확하다. ⇒ 서블릿 컨테이너 기반 WAS 이다 (jakasta EE의 모든 스펙을 지원하지 않음)

3. Dispatcher Servlet

  • Spring MVC에서 모든 HTTP 요청을 받아서 적절한 컨트롤러로 전달(dispatch)하고, 응답을 만들어 클라이언트에 반환하는 역할을 함. (가장 먼저 서블릿 컨테이너가 받은 요청을 받는 서블릿이다) ⇒ 스프링에서 단 1개만 존재한다.

Q. Dispatcher Servlet 는 스프링 프로젝트에서 1개만 존재하는데 요청이 몰리면 과부하 생기는 거 아닌가?

  • 요청마다 쓰레드가 새로 실행되기 때문에 병렬 처리됨 (쓰레드 풀은 tomcat이 실행되고 나서 200개 정도 만들어 놓음)
  • 여전히 공유 자원에 대한 동시 접근 시 문제는 발생할 수 있음.

사실 여기부터가 포스팅의 이유라고 할 수 있는데, Dispatcher Servlet가 1개라고 해서 스프링에 서블릿이 1개인가? 라고 생각했는데 아니라고 한다. 강사님께서는 필터와 인터셉터에 대해서 생각해보라고 하셨고, 이에 대해 정리를 해보았다.

4. Filter

  • 말 그대로 요청을 받아 필터링하는 역할을 한다.
  • Spring Context에 존재하지 않고 Servlet Container에 속한다. ( 의도적으로 @WebFilter + @ServletComponentScan 을 사용하면 스프링 빈으로 등록할 수 있다 )
  • Spring Security를 사용하면 OncePerRequestFilter 을 상속받게 해서 쉽게 빈으로 등록할 수 있다.
  • 서블릿 컨테이너는 요청을 받으면 HttpServletRequestHttpServletResponse 객체를 생성하고, 이를 Filter에 전달한다. Filter는 요청을 검사하여 문제가 없으면 FilterChain 을 통해 DispatcherServlet으로 전달하고, 문제가 있다면 응답을 직접 처리하고 요청 흐름을 차단한다.
  • 주로 인증, CORS, 요청 로깅, 보안 체크 등을 수행한다. (스프링과 분리되어야 하는 기능)

5. Interceptor

  • Dispatcher Servlet 이 HandlerMapping 을 하고 난 다음 컨트롤러에 요청을 전달하기 전 / 후로 가로챈다.
  • Filter와 달리 Interceptor는 Spring Context에서 관리한다. (Spring Security 을 사용하면 Filter 을 쉽게 Spring Context에서 관리할 수 있다)
  • 다음과 같은 상황에서 사용한다.
    • 세부적인 보안 및 인증/인가 공통 작업 ( 관리자만 사용할 수 있는 기능은 일반 유저들이 접근하지 못하게 막아야 한다, JWT 파싱을 통해 사용자 정보를 컨트롤러에 넘겨준다 )
    • API 호출에 대한 로깅 또는 검사
    • Controller로 넘겨주는 정보(데이터)의 가공

6. Filter, Interceptor 의 차이

  • Filter 의 경우 Request, Response 을 조작할 수 있지만, Interceptor 는 조작할 수 없다. 그 이유는 코드를 통해 확인할 수 있다.
public class MyFilter implements Filter {     
    @Override    
    public void doFilter(ServletRequest request, ServletResponse response, 
    			FilterChain chain) throws IOException, ServletException {        
    // 다른 request와 response를 넣어줄 수 있음        
    chain.doFilter(request, response);    
}}
  • Filter 의 경우 다음 Filter 을 호출하기 위해 Filter Chaining( 다음 Filter 을 호출 ) 을 해야 하는데, 이때 우리가 원하는 Request, Response 을 넘겨줄 수 있다.
public class MyInterceptor implements HandlerInterceptor {     
    public boolean preHandle(HttpServletRequest request, 
    HttpServletResponse response, Object handler) throws Exception {
    // Request, Response를 교체할 수 없고 boolean 값만 반환 가능        
    return true;    
}}
  • Dispatcher Servlet 이 여러 인터셉터 목록을 가지고 있고, 순차적으로 실행시킨다.그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다.그러므로 다른 request, response 객체를 넘겨줄 수 없다.

7. 정리

  • Filter, Interceptor 모두 비즈니스 로직과 분리되어 특정 요구사항을 만족해야 할 때 사용한다.
    - Filter 의 경우 특정 요청과 컨트롤러에 관계없이 전역적으로 처리해야 하는 작업이나 웹 어플리케이션에 전반적으로 사용되는 기능을 구현할 때 적용한다.
    - Interceptor 의 경우 클라이언트의 요청과 관련된 작업에 대해 추가적인 요구사항을 만족해야 할 때 적용한다.

    개인적인 궁금증이었던 Filter, Interceptor 모두 서블릿인가? 에 대한 대답은 No인 듯 하다.. 2개 모두 Servlet을 보조해줄 뿐 Servlet 은 아니라는 생각이 들었다. 엄격히 말하자면 (서블릿은 HTTP 요청을 처리해 응답을 만드는 것이라는 개념만 보면) Filter 는 서블릿이라고 볼 수 있을 거 같다. 뭔가 찜찜한 마무리? 하지만 정리는 좋았죠?

profile
공유하며 성장하는 Spring 백엔드 취준생입니다

0개의 댓글