ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CS] DispatcherServlet, filter, interceptor
    Computer Science/CS 2024. 4. 29. 15:54
    728x90

    Servlet

    서블릿은 자바 언어를 웹 애플리케이션에서 개발하기 쉽게 하기 위해 만든 API이다.

    자바 웹 페이지를 접근하기 위한 API를 제공한다.

     

    DispatcherServlet

    Dispatcher는 "급파자", "보내다" 라는 의미이다.

    → 가장 먼저 요청 받고, 처리할 컨트롤러를 찾아서 정해주는 역할이다.

     

    클라이언트로부터 어떠한 요청이 오면 톰캣과 같은 서블릿 컨테이너가 요청을 받게 된다.

    그리고 이 모든 요청을 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 된다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야하는 컨트롤러를 찾아서 작업을 위임한다.

     

    FrontController는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러로써, MVC구조에서 함께 사용되는 디자인 패턴이다.

     

     

    장점

    디스패처 서블릿이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리하면서 편리하게 이용할 수 있게 되었다. 컨트롤러를 구현해두기만 하면 디스패처 서블릿이 알아서 적합한 컨트롤러로 위임 해주는 구조가 되었다.

     

    상속

    디스패처 서블릿의 상속 구조는 아래와 같다.

    java.lang.Object
    	jakarta.servlet.GenericServlet	
    		jakarta.servlet.http.HttpServlet
    			org.springframework.web.servlet.HttpServletBean
    				org.springframework.web.servlet.FrameworkServlet
    					org.springframework.web.servlet.DispatcherServlet

     

     

    GenericServlet

      ● 프로토콜에 독립적인 일반 서블릿

     

    HttpServlet

        웹 사이트에 적합한 HTTP서블릿

        HttpServlet의 하위 클래스는 아래 메소드 중 최소 하나의 메소드를 재정의 해야 한다.

          doGet(), doPost(), doDelete()

          init(), destory()   :  서블릿 라이프 사이클의 초기화 및 파기

          getServletInfo()  : 서블릿에 대한 정보

     

    HttpServletBean

      HttpServlet의 단순 확장 클래스로 Spring이 구현한 모든 서블릿 유형에 적합한 서블릿

     

    FrameworkServlet

        스프링 웹 프레임워크의 기본 서블릿

        하위 클래스는 요청을 처리하기 위해 doService()메서드를 구현해야 한다.

     

    DispatcherServlet

        HTTP요청을 처리하는 중앙 집중형 Dispatcher ( Front Controller)

        Mapping, Adapter, Exception 관련 클래스

          ▷ HandlerMapping - RequestMappingHandlerMapping

          HandlerAdapter  - RequestMappingHandlerAdapter

          HandlerExceptionResolver - ExceptionHandlerExceptionResolver

     

    DispatcherServlet이 등장하기 전에는 개발자가 모든 요청에 매핑되는 서블릿을 HttpServlet을 상속받아 생성했다. 

     

    설정

    모든 서블릿, 디스패처 서블릿은 자바나 Web.xml을 통해 등록 및 초기화 되어 있어야 사용 가능하다.

     

    web.xml파일은 Servlet컨테이너 초기화 작업, DispatcherServlet초기화 작업, Spring 컨테이너를 구성하기 위해 필요한 빈 정보들이 들어있는 xml파일이다.

     

    web.xml 파일을 로드하는 작업(ContextLoaderListener)을 진행한다.

     

    스페셜 빈

    special bean

    디스패처 서블릿은  요청을 처리하기 위해 위임 컴포넌트에 실제 작업을 맡긴다.

    이런 위임 컴포넌트를 스페셜 빈이라고 부른다.

     

    스페셜 빈은 프레임워크 계약을 규현하는 스프링 관리 객체 인스터스를 의미한다.

    스프링에서 제공하는 주요 빈이다. 

    스페션 빈마다 제공되는 설정들이 있지만 사용자가 재정의하거나 교체가 가능하다

     

    디스패처 서블릿에서 사용하는 스페션 빈들은 다음과 같다.

    1. handlerMapping : 요청을 처리할 컨트롤러를 찾는다.

    2. handlerAdapter : 요청을 컨트롤러로 전달한다.

    3. handlerExceptionResolver : 요청에 대한 예외 발생 시 처리해준다.

                                                     ( 핸들러 매핑 도중, 컨트롤러 실행 도중)

    4. viewResolver : 리턴값에 대한 뷰 컴포넌트를 반환한다.

                                 String으로 이름을 전달받았을 때 이를 modelAndView 등의 객체로 반환한다.

    5. LocalResolver : Locale을 결정한다.

                                  Locale : 유저의 언어, 지역, 출력 형식 등을 정의

    6. MultipartResolver : 멀티파트 파일 업로드를 처리한다.

                                        멀티파트: HTTP응답의 바디를 여러 파트로 나눠서 보내줄 때의 파일 형식

     

     

     

    동작 과정

    디스패처 서블릿은 스프링MVC의 중앙 서블릿이며 어플리케이션으로 오는 모든 요청을 핸들링하고 공통 작업을 처리해준다.

    맨 앞단에서 처리함으로 Front Controller라고도 불린다.

     

     

    디스패처 서블릿의 동작 과정

     

    1. DispacherServlet이 클라이언트의 모든 요청을 받는다.

    2. 요청 정보에 대해 HandlerMapping에 위임하여 처리할 Handler(Controller)를 찾는다.

    3. 2번에서 찾은 Handler를 수행할 수 있는 HandlerAdapter를 찾는다,

    4. HandlerAdapter는 Controller에 비즈니스 로직 처리를 호출한다.

    5. Controller는 비즈니스 로직을 수행하고, 처리 결과를 Model에 설정하며 HandlerAdapter에 View name을 반환한다.

      ( 모델을 반환하면 View가 렌더링되고, 그렇지 않으면 view가 렌더링 되지 않는다.)

    6. 5번에서 반환받은 view name을 ViewResolver에게 전달하고, ViewResolver는 해당하는 View객체를 반환한다.

    7. DispacherServlet은 View에게 Model을 전달하고 화면 표시를 요청한다.

    8. 서버의 응답을 클라이언트에게 반환한다.

     

    filter

    J2EE표준 스펙 기능

    HTTP 요청과 답을 변경할 수 있는 재사용 가능한 클래스

    필터는 객체 형태로 존재한다.

    클라이언트와 자원 사이에 위치하여 실제 자원(JSP, 서블릿 등)이 받는 요청 정보는 필터가 변경한 요청 정보가 되며, 클라이언트가 보는 응답 정보는 필터가 변경한 응답 정보가 된다.

     

    필터는 정보를 변경할 뿐만 아니라 흐름도 변경할 수 있다.

    필터는 디스패처 서블릿에 요청이 전달되기 전/후에 URL패턴에 맞는 모든 요청에 대해 부가적인 작업을 처리할 수 있는 기능을 제공한다.

    디스패처 서블릿은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러로, 필터는 스프링 범위 밖에서 처리가 된다는 것이다!!

    -> 즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너(서블릿 컨테이너)에 의해 관리가 되는 것이고(스프링 빈으로 등록은 된다), 디스패처 서블릿 전/후에 처리한다.

     

     

    필터 구현의 핵심 3가지 타입

    ● Javax.servlet.Filter 인터페이스

        클라이언트와 최종 자원 사이에 위치하는 필터를 나타내는 객체가 구현해야 하는 인터페이스

        ○ Init() : 필터 초기화 작업

        ○ doFilter() : 필터 역할

        destory() : 필터가 사용한 자원 반납

    ● Javax.servlet.ServletRequestWrapper 클래스

    ● Javax.servlet.ServletResponseWrapper 클래스

     

     

    필터 설정하는 2가지 방법

    web.xml

       filter, filter-mapping로 매핑

    ● @WebFilter어노테이션 이용 

        속성

         urlPatterns : 필터를 적용할 URL패턴 적용

         servletNames : 필터를 적용할 서블릿 이름 목록 지정

         filterName : 필터의 이름 지정

         initParams : 초기화 파라미터 목록 지정

         dispatcherTypes : 필터를 적용할 범위 지정

     

    필터의 응용

    사용자 인증

    캐싱 필터

    자원 접근에 대한 로깅

    응답 데이터 변환(HTML변환, 응답 헤더 변환, 데이터 암호화 등)

    공통 기능 실행

     

    Interceptor

    Spring이 제공하는 기술

    디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공

    즉, 웹 컨테이너(서블릿 컨테이너)에서 동작하는 필터와 달리 인터셉터는 스프링 컨텍스트에서 동작을 하는 것이다.

    https://mangkyu.tistory.com/173

    디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다. 그래서 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.

     

    인터셉터는 스프링 컨테이너 내에서 동작하므로 필터를 거쳐 프론트 컨트롤러인 디스패처 서블릿이 요청을 받은 이후에 동작하게 된다.

     

    인터셉터의 메소드

    인터셉터를 추가하기 위해서는 HandlerInterceptor인터페이스를 구현해야한다.

    HandlerInterceptor에서 선언된 3가지 메소드가 있다.

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

     

    ● preHandler 메소드

     preHandle메소드는 컨트롤러가 호출되기 전에 실행된다. 그렇기 때문에 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.

    preHandle의 3번째 파라미터인 handler파라미터는 핸들러 매핑이 찾아준 컨트롤러 빈에 매핑되는 HandlerMehtod라는 새로운 타입의 객체로써, @RequestMapping이 붙은 메소드의 정보를 추상화한 객체이다.

    또한 preHandle의 반환 타입은 boolean인데 반환 값이 true이면 다음 단계로 진행되지만, false라면 작업을 중단하여 이후의 작업(다음 인터셉터 또는 컨트롤러)은 진행되지 않는다.

     

    ● postHandler 메소드

    postHandle메소드는 컨트롤러를 호출된 후에 실행된다. 그렇기 때문에 컨트롤러 이후에 처리해야하 하는 후처리 작업이 있을 때 사용할 수 있다. 이 메소드는 컨트롤러가 반환하는 ModelAndView타입의 정보가 제공되는데, 최근에는 JSON형태로 데이터를 제공하는 RestAPI기반의 컨트롤러(@ResController)를 만들면서  자주 사용되지는 않는다.

    또한 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하면 postHandle은 호출되지 않는다.

     

    ● afterCompletion 메소드

    모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다.

    요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다.

    postHandler와 달리 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하더라도 afterCompletion은 반드시 호출된다.

     

    인터셉터와 AOP

    인터셉터 대신 컨트롤러들에 적용할 부가가능을 어드바이스로 만들어 AOP를 적용할 수도 있다. 하지만 다음과 같은 이유들로 컨트롤러의 호출 과정에 적용되는 부가기능들은 인터셉터를 사용하는 편이 낫다.

    1. 컨트롤러는 타입과 실행 메소드가 모두 제각각이라 포이트컷(적용할 메소드 선별)의 작성이 어렵다.

    2. 컨트롤러는 파라미터나 리턴 값이 일정하지 않다.

    3. AOP에서는 HttpServletRequest/Response 객체를 얻기 어렵지만 인터셉터에서는 파라미터로 넘어온다.

     

    filter vs interceptor

    Filter → DispatcherServlet   → Interceptor 순서로 요청이 전달된다.

    Filter가 Interceptor보다 클라이언트의 요청을 먼저 받아들인다.

    대상 필터 인터셉터
    관리되는 컨테이너 서블릿 컨테이너 스프링 컨테이너
    스프링의 예외처리 여부 X O
    Request/Response
    객체 조작 가능 여부
    O X
    용도 공통된 보안 및 인증/인가 관련 작업
    모든 요청에 대한 로깅 또는 검사
    이미지/데이터 압축 및 문자열 인코딩
    Spring과 분리되어야 하는 기능
    세부적인 보안 및 인증/인가 공통 작업
    API호출에 대한 로깅 또는 감사
    Contorller로 넘겨주는 정보의 가공

     

     

    관리되는 컨테이너

    필터와 인터셉터는 관리되는 영역이다르다.

    필터는 스프링 이전의 서블릿 영역에서 관리되지만, 인터셉터는 스프링 여역에서 관리된다.

    필터는 스프링이 처리해주는 내용들을 적용 받을 수 없다.

    이로 인한 차이로 발생하는 대표적인 예시가 스프링에 의한 예외처리가 되지 않는다는 것이다.

     

    필터는 현재 스프링 빈으로 등록이 가능하며, 다른 곳에 주입되거나 다른 빈을 주입받을 수도 있다.

     

    스프링 예외 처리 여부

    스프링을 사용하면 ControllerAdvice와 ExceptionHandler를 이용한 예외처리 기능을 사용한다.

    예외를 던져 404 status로 응답을 반환하면 예외가 서블릿까지 전달되지 않고 처리된다.

     

    하지만 필터는 스프링 앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 받을 수 없다.

    필터에서 Exception을 던졌다면 에러가 처리되지 않고 서블릿까지 전달된다. 서블릿은 예외가 핸들링되기를 기대하지만 예외가 그대로 올라와서 예상치 못한 Exception을 만난 상황이된다. 따라서 내부에 문제가 있다고 판단하여 500Status로 응답을 반환한다.

     

    Request/Response객체 조작 가능 여부

    필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없다.

    조작한다는 것은 내부 상태를 변경한다는 것이 아니라 다른 객체로 바꿔친다는 의미이다.

    필터는 다음 필터를 호출하기 위해 필터 체이닝을 해주어야 한다. 이때 Request/Response객체를 넘겨주므로 우리가 원하는 Request/Response객체를 넣어줄 수 있다.

     

    하지만 인터셉터는 처리 과정이 필터와 다르다.

    디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, for문으로 순차적으로 실행시킨다. 그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다. 그러므로 우리가 다른 Resqeust/Response객체를 넘겨줄 수 없다. 그리고 이러한 부분이 필터와 확실히 다른 점이다.

     

    필터와 인터셉터의 용도 및 예시

    ● 필터

    스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.

    대표적으로 보안 공통 작업이 있다. 필터는 인터셉터보다 앞단에서 동작하므로 전역적으로 해야하는 보안 검사(XSS방어)를 하여 올바른 요청이 아닐 경우 차단을 할 수 있다. 그러면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 더욱 높일 수 있다.

    또한 필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다. 

    필터는 다음 체인으로 넘기는 ServletRequest/ServletResponse 객체를 조작할 수 있다는 점에서 인터셉터보다 훨씬 강력한 기술이다.

     

    대표적으로 필터를 인증과 인가에 사용하는 도구로 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 SpringMVC에 종속적이지 않다는 것이다. 이러한 이유로 필터 기반의 인증/인가 처리를 하기 때문이다.

    필터는 스프링 빈으로 등록이 가능하며, 다른 곳에 주입되거나 다른 빈을 주입받을 수도 있다.

     

     

    ● 인터셉터

    클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리한다.

    세부적으로 적용해야 하는 인증이나 인가과 같이 클라이언트 요청과 관련된 작업 등이 있다.

    예를 들어 특정 그룹의 사용자는 어떤 기능을 사용하지 못하는 경우가 있는데, 이러한 작업들을 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.

    또한 인터셉터는 필터와 다르게 HttpServletRequest나 HttpServletResponse등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없다. 사용자의 ID기반으로 조회한 사용자 정보를 HttpServletRequest에 넣어줄 수 있다.

    그 외에도 우리는 다양한 목적으로 API호출에 대한 정보들을 기록해야 할 수 있다. 이러한 경우에 HttpServletRequest나 HttpServletResponse를 제공해주는 인터셉터는 클라이언트의 IP나 요청 정보들을 포함해 기록하기에 용이하다.

     

     

     

    참고

     

    https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html

     

    https://zzang9ha.tistory.com/441

     

    https://velog.io/@betterfuture4/Spring-Dispatcher-Servlet-%EC%A0%95%EB%A6%AC

     

    https://tecoble.techcourse.co.kr/post/2021-05-24-spring-interceptor/

     

    https://goodgid.github.io/Spring-HandlerInterceptor/

     

    https://mangkyu.tistory.com/173

     

    https://sigridjin.medium.com/servletcontainer%EC%99%80-springcontainer%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%B8%EA%B0%80-626d27a80fe5

     

    728x90

    'Computer Science > CS' 카테고리의 다른 글

    [CS] DTO Entity  (0) 2024.05.06
    [CS] Load balancing  (0) 2024.04.10
    [CS] Proxy Pattern  (0) 2024.04.09
    [CS] JSP HTTP URL  (0) 2024.04.08
    [CS] polling push pull  (0) 2024.04.02

    댓글

© 2022. code-space ALL RIGHTS RESERVED.