처음 웹 서버는 정적인 요청에 대한 응답만 가능했다. 동적인 페이지를 만들기 위해 프로그램을 붙였고 대표적인 것이 서블릿이다. 초기에는 CGI 구현체를 활용했지만 요청마다 새로운 프로세스를 만드는 것은 너무 비효율적이였다. 그래서 하나의 싱글톤 CGI 구현체를 사용함으로써 스레드로 처리할 수 있게 되었고 이것이 현재의 서블릿이 된 것이다.
Spring Web MVC는 서블릿을 사용한다. 그럼 이 둘을 비교하는게 맞을까도 싶다. 그래서 서블릿과 서블릿을 사용한 Spring Web MVC에 대해 기록해보려고 한다.
그림과 같은 http 요청과 응답을 개발자가 직접 처리하기 위해 응답을 만들고 하는 과정을 거친다면 힘들 것이다. 모든 규약을 확인해가며 긴 텍스트로 들어온 요청을 분석하고 거기에 맞는 처리를 하고 처리한 값을 또 규약에 맞춰서 응답으로 만들어 보내줘야한다. 하지만 서블릿을 쓴다면 HttpServletRequest.getMethod(); 로 http 형태의 요청을 직접 파싱할 필요가 없어졌다. 서블릿이 요구하는 구현 규칙을 지켜주면서 서블릿을 정의해주면 손 쉽게 요청과 응답을 처리할 수 있다. 이 말은 즉슨 개발자는 가운데 있는 처리 로직에만 더 집중할 수 있게 된 것이다.
서블릿은 생성되면 init, 소멸할 때는 destory 메서드가 호출된다. 우리는 이 service 즉 요청에 대한 처리에 신경쓰면 된다.
service에 큰 흐름을 살펴보면 각 요청에 따른 doXXX메소드를 호출하게 된다. 우리는 doXXX()를 재정의해주면 되는 것이다.
조금만 더 서블릿에 들어가보자. 서블릿 컨테이너는 무엇이고 서블릿이 호출되는 과정은 어떻게 될까?
서블릿 컨테이너는 그냥 쉽게 서블릿을 담고 있는 컨테이너이다. * Tomcat (WAS)이 관리
사용자 요청이 들어오면 해당 요청과 매핑된 서블릿을 찾게 된다. 어떤 요청과 매핑되어 있는지 어떻게 알 수 있을까?
설정파일에 다 정의가 되어있다.
해석해보면 HelloServlet은 servlet에 클래스 파일로 정의가 되어있고 /hello에 요청이 들어오면 HelloServlet으로 처리를 한다는 것이다. 요청이 들어오면 그에 맞는 servlet 인스턴스가 컨테이너에 있는지 확인을 하고 존재한다면 인스턴스를 그대로 사용하고 없다면 init() 메소드를 호출해서 생성하는 것이다. 그리고 서블릿 컨테이너에 스레드를 생성하고 HttpServletResponse와 HttpServletRequest 객체를 인자로 서비스를 호출하는 것이다.
그럼 이 서비스를 호출했을 때 이부분에서 우리가 정의한 요청처리 로직이 수행되는 것이다. Respone, Request 객체는 생성하고 소멸되는데 Servlet은 생성만하고 소멸시키는 동작은 하지 않고 있다. 서블릿이 싱글톤으로 관리가 되고 있기 때문이다. 소멸되지 않고 있다가 다음 번 같은 요청이 들어올 때 호출되는 것이다. 서블릿 컨테이너는 이렇게 서블릿의 생명주기를 관리하는 것이다. 개발자가 아닌 서블릿 컨테이너에게 위임을 하는 것이다.
만약 여러 요청이 들어온다면 다른 요청을 처리할 일이 생기면 멀티스레드로 처리를 하게 된다. 멀티스레드의 경우 비용도 많이 들고 컨텍스트 스위칭(A스레드에서 B스레드로)이 일어난다면 많은 오버헤드를 일으킨다. 스레드 생성에 제한을 두지 않으면 그만큼 많은 스레드를 생성하다가 서버의 하드웨어 환경을 넘어버리면 서버가 터질 수도 있다.
개발자의 입장에서 봐도 핸들러의 공통 로직이 매번 중복된다.
요청을 앞단에서 처리할 수 있도록 공통 로직을 분리해 앞단에 둔 것이 프론트 컨트롤러 패턴이다. 스프링 MVC도 프론트 컨트롤러 패턴을 따르고 모든 요청을 받는 전면 컨트롤러를 Dispatcher Servlet이라고 부른다. 서블릿은 하나만 두고 모든 요청을 다 받을 수 있도록 하는 것이다. 설정파일도 모든 URL에 대해 정의하고 사용한다.
이전에는 요청마다 서블릿을 정의하고 요청을 수행할 때마다 매번 스레드를 생성했다면 이제는 하나의 서블릿만 정의하고 모든 요청을 처리할 수 있는 것이다.
앞단의 공통 로직의 수행을 분리한 결과 이러한 구조가 나오게 된다. 스프링 MVC 패턴 (https://sh970901.tistory.com/37)
스프링에서는 위 구조가 다 인터페이스이고 구현체들도 정의되어있어 우리는 컨트롤러 혹은 핸들러만 구현하면 되는 것이다. 즉 비즈니스 로직에 더욱 집중할 수 있게 된 것이다. 스프링 없이 개발을 했다면 ViewResolver, Handler Mapping, Handler Adapter 등을 모두 직접 처리했어야하는 부분이다. 이 역할을 하는 객체들은 Dispatcher Servlet이 스프링 컨테이너로부터 주입을 받아서 사용하고 동작을 하게 된다.
즉 스프링으로 웹 요청을 처리한다는 것은 스프링 mvc에서 제공하는 Dispatcher Servlet과 웹 요청 처리 관련 구현체들을 사용할 수 있다는 이야기와 동시에 스프링 컨테이너, 즉 스프링 IoC를 사용해서 개발할 수 있다는 것이다.
'IT' 카테고리의 다른 글
OSI 7계층 (TCP/IP 4계층) (1) | 2022.11.30 |
---|---|
스프링(Spring) VS 스프링부트(SpringBoot) (0) | 2022.11.30 |
SQL과 NoSQL (0) | 2022.11.27 |
인덱스(INDEX)의 필요성 (1) | 2022.11.23 |
[JAVA] next(), nextLine(), 입력과 버퍼 (0) | 2022.11.17 |