Spring Servlet 동작 원리

클라이언트가 서버와 통신하기 위해 특정 포트번호 요청을 보내어 소켓 통신을 맺고, HTTP 요청에 대한 데이터를 가공하여 WAS 에게 정제된 데이터를 전달한다.

이 모든 과정을 생략하고 스프링 부트 라는 마법 뒤에서 개발하였으나, 스프링의 내면에는 이런 과정이 숨어있다.

서블릿

특정 URL 경로와 매핑되어, 클라이언트의 HTTP 요청을 처리하고 그 결과를 다시 반환하는 역할을 수행하는 자바 객체이다.

@WebServlet(name = "helloServlet", urlPatterns = "/hello") // /hello 경로로 요청이 오면 해당 서블릿이 실행 됨  
public class HelloServlet extends HttpServlet {  
  
    @Override  
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        String username = request.getParameter("username");  
        System.out.println("username = " + username);  
  
        response.setContentType("text/plain");  
        response.setCharacterEncoding("utf-8");  
        response.getWriter().write("hello " + username);  
    }  
}
📑

정리하기 서블릿을 통해 사용자가 요청하는 경로에 맞게 처리하는 과정은 굉장히 복잡하다.

HttpServeltRequest 의 헤더 정보, 쿼리 파라미터 정보, 메시지 영역의 JSON 형식, 쿠키 등을 직접 접근하여 가공해야 하는 번거로움이 있다.

반대로, HttpServletResponse 를 통해 헤더 정보, 응답 메시지 정보, 쿠키 정보 등을 조작할 수 있다.

이런식으로 사용자가 요청하는 경로를 처리할 때 마다 복잡한 코드를 모두 포함하고 있다면 반복적인 요청과 응답을 가공하고 지정하는 방식이 반복되게 된다.

서블릿이 과거 기술이기도 하지만, 이런 반복적인 코드를 편리하게 조작하고자 스프링 MVC 에서 기능을 제공한다.

서블릿 컨테이너

사용자가 보내는 모든 요청을 처리할 수 있도록 서블릿 객체의 생명 주기를 관리하는 환경이며, 클라이언트의 요청이 들어오면 네트워크 통신을 처리하고 해당 요청을 처리할 서블릿을 실행하며, 멀티 스레딩 환경에서 여러 요청을 한 번에 처리할 수 있는 기술이다.


프론트 컨트롤러 패턴은 기존에 서블릿 MVC 가 갖고 있던 공통 로직 처리에 대한 관리가 어려워, 반복적인 코드 작성이 발생했던 단점을 보완 하고자 나왔다.

프론트 컨트롤러라는 서블릿을 기존 요청을 처리해야 할 서블릿보다 한 계층 앞에서 요청을 먼저 받아, 로직을 처리한 뒤 요청 URL 을 처리해야 할 서블릿을 호출한다.

특징

  • 프론트 컨틀로러 서블릿 하나로 클라이언트의 요청을 받는다.
  • 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출한다.
  • 요청하는 창구가 다양해지지 않고, 프론트 컨트롤러 하나로 줄어든다.
  • 요청을 받는 프론트 컨트롤러는 다른 컨트롤러를 호출하기 전 공통으로 처리해야 할 로직을 수행할 수 있다.
  • 프론트 컨트롤러를 제외한 나머지는 서블릿 객체를 상속 받아서 서블릿 인스턴스를 만들 필요가 없다.

중요

  • 스프링 웹 MVC 의 핵심은 FrontController 이다.
  • 스프링 웹 MVC 의 DispatcherServletFrontController 로 구현되어 있다.

ℹ️

디스패처 서블릿이란? DispatcherServlet 은 컨트롤러의 요청을 먼저 받아 공통적인 로직을 처리한 뒤 사용자 요청에 맞는 컨트롤러를 호출하는 프론트 컨트롤러의 역할을 하는 객체이다.

프론트 컨트롤러를 사용했을 때 장점


  1. Servlet Container 가 네트워크 처리와 HTTP 가공 후 해당 요청을 처리 할 Dispatcher Servlet을 연결한다.
  2. Dispatch Servlet 은 특정 URL 에 대한 행위를 처리할 수 있는 핸들러를 찾기 위해 HandlerMapping 객체에게 위임한다.
    • HandlerMapping 은 컨트롤러에 @RequestMapping 어노테이션이 있는 메서드를 기반으로 연관된 컨트롤러를 찾는다.
  3. HandlerMapping 객체가 찾은 컨트롤러를 DispatchServlet 에게 반환하고, DispatchServlet 은 HandlerAdapter를 통해 핸들러를 처리할 수 있는 어댑터를 조회한다.
  4. HandlerAdpater 는 핸들러가 반환하는 정보를 ModelAndView 로 변환해서 DispatchServletd 에게 반환한다.
  5. DispatchServlet 은 뷰 컨텐츠를 가져오는 ViewResolver 에게 위임하여, 어떤 View 를 실행 해야하는지 조회하여 View를 반환한다.
  6. View 는 ModelAndView 의 정보를 렌더링한 뒤 결과물을 HTTP 응답으로 반환하게 된다.