스프링 프로젝트를 생성하면 기본적으로 생성되는 web.xml에 대해서 알아보겠습니다. 이 포스팅은 Spring Starter Project가 아닌 Spring Legacy Project 기준으로 작성되었습니다.

 

 

 들어가기 전에

  • 포스팅에서 web.xml은 "Servers/server_name-config/web.xml"이 아닌 "src/main/webapp/WEB-INF/web.xml"이다.
  • WAS를 Servlet Container로 부르기도 하지만 여기서는 서블릿을 관리하는 서버 사이드의 웹 어플리케이션으로 구분짓는다. 즉, WAS(혹은 톰캣)와 서블릿 컨테이너는 구분된다.
  • Servlet Container = (Web Container)
  • Spring Container = (Application Context, Application Container, IoC Container, Singleton Container)

 

 

 

 web.xml 

 web.xml 파일은 배포 설명자(DD; Deployment Descriptor)라고 불린다. "src/main/webapp/WEB-INF/web.xml"에 위치한 이 파일은 웹 어플리케이션 실행 시 메모리에 로딩되는데 서버를 구동될 때 메모리에 로딩되어야 할 설정(객체) 등이 정의되어 있다. 스프링 프로젝트의 web.xml은 기본적으로 Context Loader Listener와 Dispatcher Servlet에 대한 설정이 정의되어 있다. 기본 설정 외에도 필요에 따라 서블릿, 필터를 정의할 수도 있다.

 

 

 웹 어플리케이션은 반드시 단 하나의 web.xml을 가져야 하기 때문에 아파치 톰캣 + 스프링 프레임워크로 구성된 서버에서는 톰캣의 web.xml과 스프링 프레임워크의 web.xml 총 2개가 생성된다. 

 

 

 web.xml에 정의 해놓은 설정들은 서버가 구동될 때 메모리에 올라가는 것도 있고 사용자의 요청에 따라 호출되었을 때 비로서 메모리에 올라가는 것도 있다. 이 부분에 대해서는 아래에서 흐름에 맞게 설명할 것이다.

 

web.xml

 [6~9] root-context.xml의 경로를 파라미터로 등록한다. 여기서 정의된 파라미터는 Servlet Context 객체에서 읽어올 수 있다.

  • <context-param> 태그를 사용하면 스프링 컨테이너에서 사용 할 수 있는 파라미터를 선언할 수 있다.
  • <param-name> 태그는 <context-param>에 대한 식별자를 지정한다.
  • <param-value> 태그는 <context-param>에 대한 값을 지정한다.

 [11~13] Context Loader Listener는 위에서 생성한 "contextConfigLocation" 파라미터를 참조하여 루트 컨텍스트를 생성한다.

 

 [15~23] <servlet> 태그 내에 생성된 "contextConfigLocation" 파라미터를 참조하여 Dispatcher Servlet에 관련된 컨텍스트를 생성한다.

  • <servlet> 태그는 Servlet을 상속받아 작성된 클래스를 서블릿으로 등록한다.
  • <servlet-name> 태그는 서블릿의 식별자를 지정한다.
  • <servlet-class> 태그는 서블릿으로 등록할 클래스를 지정한다. 반드시 패키지 이름까지 풀네임으로 적어줘야 한다.
  • <init-param> 태그는 서블릿 초기화에 사용될 파라미터를 설정한다. 이 경우 디스패처 서블릿이 객체화되고 초기화를 위해 init() 메서드가 호출될 때 참조될 설정 파일의 경로를 파라미터 값으로 설정하며 1개 이상의 파라미터를 설정할 수 있다. <context-param>과 다른 점은 <servlet>내에 선언된 만큼 참조 범위가 해당 서블릿 내로 제한된다.
  • <load-on-startup>태그는 주어진 값이 1 이상일 경우 서버 구동 시 서블릿이 바로 메모리에 올라갈 수 있도록 한다. 여기에서 값은 서블릿의 로드 순서(혹은 우선순위)를 나타내는데 숫자가 높을수록 우선순위가 낮다.

 [25~28] : 앞서 [15~23]에서 등록한 Dispatcher Servlet에 대한 URL을 매핑한다. <servlet-mapping>은 web.xml에 등록한 서블릿 이름과 클라이언트로부터 받는 url을 매핑할 수 있다.

  • <servlet-mapping> 태그는 등록한 서블릿에 대한 URL을 매핑하기 위해 사용한다.
  • <servlet-name> 태그는 매핑할 서블릿 이름(위에서 설정한 식별자)을 지정한다.
  • <url-pattern> 태그는 지정한 서블릿이 어떤 URL에 매핑될 것인지를 지정한다. 기본적으로 루트("/")에 매핑되어 있기 때문에 모든 URL이 매핑 대상이 된다. 평소 와일드 카드 문자(*)에 익숙한 사람이라면 '/'가 아니라 '/*' 아닌가라는 생각을 할 수 있지만 '/'를 사용하는 것이 맞다.

 

 

 

 Context Loader Listener

web.xml의 일부

 <context-param>은 서블릿 컨텍스트에 파라미터를 등록할 수 있으며 필요에 따라 파라미터를 추가할 수 있다. 자바에서 변수를 선언하듯 param-name으로 이름을 부여하고 값으로 설정 파일(root-context.xml)의 경로를 부여하여 파라미터 이름을 통해 설정 파일에 접근할 수 있게 한다. 

 

 

 Context Loader Listener는 스프링 컨테이너를 생성하고 컨테이너에 루트 컨텍스트를 생성한다. <listener-class>값을 보면 컨텍스트 로더 리스너가 추상적인 개념이 아닌 실제 클래스임을 알 수 있고 패키지 명을 보면 스프링 프레임워크에서 제공하는 클래스임을 알 수 있다. 컨텍스트 로더 리스너는 org.springframework.context.ApplicationContext 인터페이스를 구현하는 것으로 스프링 컨테이너를 생성한다. 또한 이 때 위에서 생성한 파라미터 contextConfigLocation을 읽어서 설정 파일(root-context.xml)에 정의된 bean을 컨테이너에 생성하는 것이다.

 

 

 web.xml에서 둘은 연관성을 찾아볼 수 없지만 ContextLoaderListener 클래스가 상속받고 있는 ContextLoader 클래스를 들여다보면 일부 메서드가 ServletContext를 통해 contextConfigLocation 파라미터에 접근하는 것을 볼 수 있다.

 

 

 

 Dispatcher Servlet

  • web.xml에서 초기화, 실행되도록 정의되어 있다.
  • 디스패처 서블릿 역시 Servlet이기 때문에 서블릿 컨테이너에 생성된다.
  • 모든 요청은 컨트롤러로 가기 전에 디스패처 서블릿을 거쳐야 한다.
  • 컨트롤러들이 공통적으로 수행해야 하는 작업을 처리한 뒤 적절한 컨트롤러로 요청을 넘긴다.
  • 디스패처 서블릿이 공통된 작업을 처리해주기 때문에 각 컨트롤러는 비지니스 로직 처리에만 집중할 수 있다. 이렇게 하나의 컨트롤러를 놓고 모든 요청을 한 곳으로 집중, 일괄 처리하는 디자인 패턴을 Front Controller 패턴이라 한다.
  • 요청에 해당하는 컨트롤러를 찾는 작업은 HandlerMapping에게 위임하고 결과를 반환받는다. 다시 HandlerMapping에게 받은 데이터를 HandlerAdapter에게 전달하여 컨트롤러 실행을 위임한다.
  • 컨트롤러는 실행 결과로 JSON, XML, View 등을 반환하는데 View가 반환될 경우 사용자에게 표시될 View 파일(*.html, etc)의 이름을 전달받는다. 이 데이터를 ViewResolver 객체에게 전달하여 실제 View를 찾는다.
  • 모든 서블릿을 파싱하여 Map 형태(Key-Value)로 관리한다.
  • 1개 이상의 디스패처 서블릿이 존재할 수 있으며 디스패처 서블릿은 각자의 서블릿 컨텍스트를 갖는다.

 

web.xml의 일부

 

 디스패처 서블릿은 "src/main/webapp/WEB-INF/web.xml"에 정의되어 있다. <servlet-class>의 값을 보면 디스패처 서블릿은 추상적인 개념이 아니라 클래스로 존재한다는 것을 알 수 있고 패키지 명을 보면 자바가 아닌 스프링 프레임워크에서 제공하는 클래스면서 디스패처 서블릿 역시 서블릿의 한 종류라는 것을 알 수 있다.

 

 

 디스패처 서블릿도 컨텍스트 로더 리스너와 마찬가지로 설정 파일의 경로를 파라미터로 생성, 참조하여 스프링 컨테이너에 컨텍스트를 생성하게 된다. 스프링 컨테이너에 컨텍스트를 생성하는 것은 다름이 없지만 생성 과정에서 다소 차이가 있는데 디스패처 서블릿은 org.springframework.web.context.WebApplicationContext 인터페이스로 컨텍스트를 구현한다. 또한 컨텍스트 로더 리스너와 달리 파라미터가 서블릿 태그 내부에 선언되었기 때문에 디스패처 서블릿이 생성하는 컨텍스트의 bean들은 외부에서 참조가 불가능하다는 차이가 있다.

 

 

 설정 파일을 파라미터로 선언함에 있어 차이를 보이는 것은 그냥 어쩌다보니 그렇게 된 것이 아니라 의도적으로 설계된 것이다. 계층 아키텍쳐에서 비지니스 로직을 처리하는 객체들이 View에 해당하는 객체들을 참조할 수 없도록하고 반대는 가능하도록 참조 관계를 나눈 것이다. 이는 부모 관계로도 표현할 수 있는데 root-context.xml에 정의된 bean들이 부모, servlet-context.xml에 정의된 bean들이 자식에 해당한다. 부모 클래스는 자식 클래스에 있는 변수, 메서드의 존재를 알 수 없기 때문에 접근이 불가능한 반면 자식 클래스는 부모 클래스를 물려받았기 때문에 부모 클래스에 있는 변수, 메서드에 접근할 수 있다. 왜 이렇게 나누어졌느냐고 묻는다면 이유는 간단하다. 컨트롤러는 비지니스 로직을 처리하기 위해서 서비스를 호출해야만 하는 반면 서비스나 DAO는 뷰를 직접 호출할 일이 없기 때문이다.

 

 

 

 

 Dispatcher Servlet이 메모리에 올라가는 시점

 일반적인 서블릿이 메모리에 올라가는 시점, 즉 객체화되는 시점은 클라이언트로부터 요청이 발생했을 때다. 어노테이션 혹은 web.xml에 등록되어 있다가 해당 서블릿에 대한 요청이 발생하면 객체화되고 int()을 호출하여 초기화된다. 디스패처 서블릿도 서블릿이지만 일반적인 서블릿과는 달리 웹 어플리케이션 구동 시 객체화되는데 일반적인 서블릿을 등록하는 방식과 다르지 않음에도 불구하고 서버 구동 시 바로 객체화되는 이유는 <load-on-startup> 태그 때문이다. 이 태그의 값이 0보다 클 경우 서블릿 컨테이너가 생성 및 초기화될 때 해당 서블릿이 같이 초기화된다.

 

 

 디스패처 서블릿이 서블릿과 달리 서버 구동 시에 객체화되어야 하는 이유는 무엇일까? 서블릿은 기본적으로 해당 서블릿에 대한 요청이 발생해야만 객체화되는데, 이 말은 어떤 서블릿은 서버가 구동되고 나서 한 번도 호출되지 않을 수 있다고도 해석될 수 있다. 반면 디스패처 서블릿은 프론트 컨트롤러이기 때문에 어떠한 요청이라도 반드시 호출된다. 서블릿은 최초 요청이 발생했을 때 메모리에 올리는 시간이 소모되기 때문에 요청이 있는 한 반드시 호출되는 디스패처 서블릿을 사전에 등록하여 요청이 발생했을 때 메모리에 올리는 시간을 없애주고 즉시 사용을 보장해주는 것이다.

 

 

 

 Dispatcher Servlet 동작 과정

 디스패처 서블릿의 요청 처리과정을 이미지로 나타내었다. 기본적으로 존재하는 컴포넌트와 필수 요소만으로 최소 구성하였기 때문에 Filter, Interceptor 등은 없다.

 

  1. 클라이언트로부터 요청 발생, 웹 서버를 거쳐 서블릿 컨테이너로 요청 전달
  2. HandlerMapping 객체에게 요청 URL에 대한 컨트롤러의 존재 여부 확인, 존재한다면 컨트롤러의 이름을 요청.
  3. HandlerAdapter를 호출하여 컨트롤러 실행을 위임
  4. HandlerAdapter는 요청받은 URL과 매핑되는 Controller 호출.
  5. Controller는 비지니스 로직을 처리하기 위해 적절한 Service 호출.
  6. Service는 비지니스 로직 처리에 필요한 데이터를 요청하기 위해 DAO/Repository 호출.
  7. 데이터베이스에 데이터 조회 및 수정.
  8. 비지니스 로직을 처리한 결과가 View(의 이름)일 경우 ViewResolver를 호출하여 View를 반환.
  9. 클라이언트로 요청 결과 전달.

 Web Server, WAS

 WAS(Web Application Server)는 한마디로 정의되는 용어지만 한마디로 이해할 수 있을 만큼 쉬운 개념은 아니다. 이 포스팅에서는 WAS가 무엇인지, 왜 필요한지, 내부적으로 어떻게 요청을 처리하는지 알아볼 것이다. WAS를 이야기 하려면 Web Server를 빼놓을 수 없기에 Web Server와 함께 WAS를 풀어가도록 하겠다.

 

  • Web Application : Web Application이란 말 그대로 웹 상에서 실행되는 어플리케이션이다. 어플리케이션이 실행되는 위치에 따라 Client-side, Server-side로 나뉜다.
  • Web Server : Web Server는 클라이언트로부터 HTTP 요청을 받았을 때 정적인 컨텐츠를 제공하는 서버로 C언어로 작성되어 있다. 여기서 정적인 컨텐츠란 html, css, js, jpg, gif 등과 같이 항상 일정한 UI를 제공하는 파일을 말한다.
  • WAS : WAS는 클라이언트로부터 HTTP 요청을 받았을 때 동적인 컨텐츠를 처리, 제공하기 위한 미들웨어로 Java로 작성되어 있다. 여기서 동적인 컨텐츠란 사용자의 입력에 따라 결과가 달라지는 컨텐츠를 말한다. WAS는 Web Server의 기능도 겸하고 있으며 내부적으로 Servlet Container를 가지고 있는 것이 가장 큰 특징이다.
  • Middleware : 미들웨어란 2개의 포인트 사이에서 데이터를 주고 받을 수 있도록 매개체 역할을 하는 소프트웨어다. 
  • 3-tier Architecture : 3계층 구조란 특정 플랫폼을 3분할하여 물리적으로 구현한 것을 말한다. 여기서 특정 플랫폼이란 일반적으로 서버를 말한다. (layer = 논리적인 계층 구조, tier = 물리적 구조)

 

 

3-tier Architecture

Web Server - WAS - DB Server

 [Web Server ↔ WAS DB Server]로 나누어 3계층으로 보는 구조다. 여기서 클라이언트는 계층에 포함시키지 않고 3 계층으로 보는데 클라이언트를 포함시켜 4-tier라고 부르는 경우도 있다. 일반적으로 웹 페이지가 위와 같이 구성된다.

 

 


 

 

Client - WAS - DB Server

 [Client ↔ WAS ↔ DB Server]로 나누어 3계층으로 보는 구조로, Web Server가 별도로 존재하지 않고 WAS 가 Web Server의 역할을 같이 한다는 것이 특징이다. 웹 사이트에 접속할 때에는 URL을 통해 해당 사이트에 대한 html을 요청하고 다운받은 html을 브라우저에 표시하는 것인데 일반적인 모바일 어플리케이션의 경우 GUI가 이미 구성되어 있고 UI에 표시할 데이터만 요청한다. 이러한 경우 Web Server가 생략될 수 있고 3-tier에 클라이언트를 포함시킨 위와 같은 구성이 쓰인다고 볼 수 있다. 

 

 

 3-tier Architecture라고 해서 반드시 위와 같이 구성되는 것은 아니며 클라이언트 아래에 적어 놓은 웹이나 앱도 하나의 예시일 뿐이다. 제시한 구조 외에도 WAS가 Web Server, DB Server가 하는 일을 모두 할 수 있기 때문에 WAS만 사용하는 1-tier로 구성되기도 한다. 위에 나온 방식들은 서버를 구성하는 하나의 구조일 뿐이며 서버나 프로젝트 규모, 환경에 따라 얼마든지 구조가 달라질 수 있음을 인지하도록 하자.

 

 


 

 

 위에서 알아본 내용을 정리하면 Web Server는 정적인 컨텐츠를 처리하는 서버, WAS는 동적인 컨텐츠를 처리하기 위한 미들웨어다. 또한 서버를 환경에 따라 분할하는 것을 n-tier Architecture 라고 하며 분할의 기준은 프로젝트 규모, 환경, 제공하는 서비스 등에 따라 얼마든지 달라질 수 있다.

 

 

 

 서버를 분할하는 이유

 앞서 언급했듯 WAS는 크게 Web Server, Container 기능을 수행한다. 이 외에도 트랜잭션, 보안, 트래픽 관리, DBCP, 사용자 관리 등의 기능을 제공한다. 나열한 기능들을 살펴 보면 WAS가 Web Server, DB Server의 기능을 모두 가지고 있는 것을 알 수 있는데 WAS만으로 서버를 구성할 수 있음에도 굳이 서버를 나누는 이유가 무엇일까?

 

 

 서버를 분할했을 때 성능 측면에서 보면 처리해야 할 작업을 적절하게 나누어 처리량을 분산시키는 효과가 있다. 사용자에게 보여 줄 인터페이스에 대한 요청은 Web Server가, 비지니스 로직을 처리해야 하는 작업은 WAS가, 비지니스 로직 처리 중 DB 조작이 필요하면 DB Server에서 데이터를 읽고 쓰는 것으로 역할을 분산시킨 것이다. 이렇게 Web Server의 작업을 세분화하면 하나의 물리적인 서버에 트래픽이 집중되어 과부화가 걸리는 것을 방지할 수 있다. 그 외에도 속도, 보안, 성능 개선, 서버 장애 대처 등의 이유가 있다.

 

 

 

 Container

 WAS에 대해 검색하면 "WAS는 Web Container 혹은 Servlet Container 라고도 부른다." 라는 문장을 단골 멘트처럼 볼 수 있다. 두 개의 이명에 공통적으로 들어가 있는 Container는 위에서 WAS의 기능을 소개할 때 Web Server와 함께 등장했었다. Servlet Engines라고도 불리는 Servlet Container에 대해 알아보자.

 

  • Container : 컨테이너란 JSP, Servlet과 같은 동적인 컨텐츠를 생성하고 관리하는 서버 사이드의 소프트웨어다. 클라이언트의 요청을 받으면 Thread Pool에서 wait 상태인 스레드를 깨우고 요청에 맞는 Servlet을 찾는다. 스레드가 서블릿을 통해 요청을 처리한 결과를 컨테이너에게 반환하면 그 결과를 클라이언트에게 반환한다. 이 과정에서 Servlet의 생성, 동작, 소멸 등 Servlet에 대한 전반적인 생명 주기를 관리한다.
  • Servlet : WAS에서 동적인 컨텐츠를 처리하는 소프트웨어로 Java 언어로 작성된다. 서버가 구동된 뒤 특정 서블릿에 대한 요청이 발생할 때 비로서 메모리에 올라가며 스레드에 의해 동작한다.
  • Servlet Life cycle : 서블릿은 [int → service destroy] 의 생명주기를 갖는다. 서블릿의 생명주기는 생성부터 소멸까지 모두 컨테이너에 의해 관리된다.
  • JSP(Java Server Page) : Servlet과 유사한 기술인 JSP는 사용자에게 보여질 View(페이지)를 작성할 때 사용되며 html 기반에서 스크립트 형태로 작성된다.
  • JSP Container : JSP를 서블릿으로 변경할 때 사용되는 소프트웨어로, 서블릿으로 구현되어 있다. 
  • Thread Pool : 작업을 처리하기 위해서 특정 개수의 스레드를 생성해놓고 작업 큐에 들어오는 작업을 하나씩 할당받아 처리하는 것을 말한다. 스레드는 요청이 발생했을 때 컨테이너에 의해 실행되고 서블릿을 실행한다. Tomcat의 옛 버전(3.2 이전)에서는 작업이 발생할 때마다 스레드를 생성하고 서블릿 실행을 맡긴 뒤 작업이 끝나면 스레드를 소멸시켜주는 등 Thread에 대한 전반적인 관리가 필요했고 이는 많은 문제를 야기하였다. Thread Pool의 등장으로 스레드 관리가 훨씬 간단해졌다.
  • Filter : 서블릿 컨테이너의 서블릿은 서버의 최종 자원이라고 할 수 있다. 여러 과정을 거쳐 마지막에 요청을 처리한 뒤 클라이언트에 결과를 반환하는 요청 처리 과정의 종점인 것이다. 필터는 순서상 서블릿 앞에 존재하며 데이터를 처리하기 전, 데이터를 처리한 후에 반드시 거치게 영역이다. 서블릿을 처리하기 전에 반드시 수행해야 하는 작업(사용자 인증, 인코딩 등)을 수행하게 된다.

 

 알아본 내용을 간단하게 정리해보자. Container란 JSP, Servlet과 같이 동적인 컨텐츠를 생성 및 관리한다. 클라이언트로부터 요청이 발생하면 Thread Pool에서 대기 중인 스레드를 할당받는다. 요청을 처리하기 앞서 필터링을 수행하고 관련된 서블릿을 찾아 비지니스 로직을 처리, 다시 필터링을 거친 뒤 결과를 반환한다. 

 

 

 

 Servlet

Servlet life cycle

  • Servlet의 생명 주기는 각각 javax.servlet.Servlet 인터페이스의 init(), service(), destroy() 메서드와 같다.
    Servlet (https://docs.oracle.com/javaee/7/api/javax/servlet/Servlet.html)
  • 'init'은 해당 서블릿에 대한 요청이 최초로 발생했을 때 단 한번만 수행된다. Class Loader로 서블릿 클래스를 로딩하여 인스턴스화하고 init() 메서드가 호출된다.
  • 'service'는 해당 서블릿에 대한 요청이 발생했을 때 수행된다. 요청이 오면 service() 메서드를 수행하여 비지니스 로직을 처리하고 결과를 반환한다.
  • 'destroy'는 서버의 종료 혹은 서블릿 컨테이너가 메모리에서 소멸될 때 수행된다.
  • init()이 단 한 번만 수행되는 이유는 서블릿은 싱글톤으로 메모리에 상주하다가 서버가 종료될 때 같이 소멸하기 때문이다. 즉 init()은 생성자 역할을 하며 하나의 서블릿 객체는 JVM마다 단 하나 씩만 존재한다는 것이다.
  • 서블릿 객체는 단 하나만 존재하는데 여러 개의 요청이 하나의 서블릿을 공통적으로 실행해야 할 경우 멀티 스레딩으로 요청을 처리한다.

 

https://tomcat.apache.org/tomcat-9.0-doc/servletapi/javax/servlet/http/HttpServlet.html

  • 서블릿은 최종적으로 javax.servlet.Servlet를 구현한 HttpServlet을 상속한 클래스로 구현된다. (HttpServlet 클래스는 Servlet 인터페이스를 상속받고 있다.)
  • HttpServlet를 상속받은 클래스는 일반적으로 doGet, doPost 라는 메서드를 오버라이드하게 되는데 HTTP 프로토콜의 메서드 타입에 따라 달리 호출된다.
  • doGet, doPost 메서드는 파라미터로 HttpServletRequest, HttpServletResponse 객체를 가지는데 각각 요청 정보, 응답 정보를 가지고 있다.
  • WebSocket 어노테이션, 설정 파일(web.xml)에서 url을 매핑해줄 수 있다. 이 값은 서블릿을 식별하는 식별자가 될 것이다.

 

 

 

 WAS 동작 흐름

 WAS에서 동작을 그림으로 표현하였다. Web Server가 따로 존재하지 않고 WAS에서 Web Server 역할을 같이 한다고 가정하자. 클라이언트로부터 "http://localhost:8080/app/search?keyword=aws" 라는 요청을 받았고 "/search"는 keyword 값인 "aws" 해당하는 검색 결과를 반환해주는 서블릿이라고 가정한다.

 

 

 먼저 요청받은 URL을 파싱해보자. 

  • localhost(IP or Domain) : URL에서 ip 혹은 도메인에 해당하는 영역이다. 클라이언트와 서버가 같은 네트워크 상에 있다면 localhost를 사용한다.
  • 8080 : 서버가 사용하는 포트에 해당하는 영역이다. ip에 해당하는 컴퓨터를 찾아 간 후 8080 포트를 사용 중인 서버를 찾아간다.
  • app : 웹 어플리케이션 이름에 해당하는 영역이다. app이라는 이름을 사용 중인 웹 어플리케이션을 찾아간다.
  • /search : "/search"에 해당하는 서블릿을 찾아간다.

 

 

 동작 과정

 (빨간 화살표가 내부 흐름이며 그림의 번호는 화살표의 순서를 의미할 뿐 설명 순서와 상관없음.)

  1. 사용자가 웹 주소창에 "http://localhost:8080/app/search?keyword=aws" 요청.
  2. 클라이언트로부터 Request 발생.
  3. Web Server에 요청이 전달되었지만 동적 콘텐츠 요청이므로 요청을 패스.
  4. 작업 큐에 작업 적재.
  5. 스레드 풀에 대기 중인 스레드가 작업을 할당.
  6. 요청하는 서블릿 컨테이너에 접근, 필터링을 수행.
  7. 필터링 수행 후 "/search"와 매핑된 서블릿이 메모리에 있는지 확인.
  8. 서블릿이 메모리에 없기 때문에 Class Loader가 서블릿 클래스를 로딩.
  9. 서블릿 객체 인스턴스화. (서블릿 생명주기 - init)
  10. 비지니스 로직 처리 (서블릿 생명주기 - service)
  11. 비지니스 로직 처리 후 결과값을 반환하기 위해 필터링 수행 후 결괏값 반환.
  12. 작업이 끝난 스레드는 자원 반납.

 

 


 

 

 포스팅에 관련된 질문 혹은 잘못된 내용, 오타 등이 있다면 댓글로 말씀해주시면 감사하겠습니다.

 

 

 # 본 블로그는 불펌을 허용하지 않습니다.

+ Recent posts