본문 바로가기
Etc/JHJ 끄적끄적

[Web] 서블릿(Servlet) 이란?

by 뽀뽀이v 2020. 9. 9.

Servlet을 배우기 전에 우리는 CGI(Common Gateway Interface)에 대해서 알아야 된다. CGI는 웹서버와 사용자 프로그램을 동작시키기 위한 인터페이스이다. 즉 이것을 구현해야 웹서버와 통신을 할 수 있다.

Servlet정의를 살펴보면 '웹 프로그래밍에서 클라이언트 Request, Response를 처리할 수 있도록 반드시 구현해야 하는 인터페이스' 즉 Servlet은 자바 CGI라고 말할 수 있다.

이러한 Servlet의 생성부터 소멸까지의 일련의 과정(Life Cycle)을 관리하는 것이 Servlet Container이다. 가장 대표적인 Servlet Container는 Tomcat이 있다.

Servlet 동작과정

위의 그림에서 Servlet Container가 요청이 들어오면 Thread를 생성하고, Servlet을 다음과 같은 동작 과정으로 실행시킨다.  

Servlet 생명주기

Servlet 생명주기, 실행 순서를 관리하는 것도 Servlet Container이다. (그래... 그래서 어쩌라는 거야?)

그럼 쉽게 설명하기 위해서 다음과 같이 Servlet 구현해 보자. (Servlet Container는 Tomcat을 사용했다고 가정하자.)

// web.xml
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.test.HelloServlet</servlet-class>
</servlet>
<Servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</Servlet-mapping>

<servlet>
    <servlet-name>Car</servlet-name>
    <servlet-class>com.test.CarServlet</servlet-class>
</servlet>
<Servlet-mapping>
    <servlet-name>car</servlet-name>
    <url-pattern>/car</url-pattern>
</Servlet-mapping>


// Controller
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    ...
}

@WebServlet("/car")
public class CarServlet extends HttpServlet {
    ...
}

위의 서블릿 객체를 살펴보면 HttpServlet을 상속받고 있다. HttpServlet은 톰캣이 구현해 놓은 서블릿 객체다.

(HttpServlet 문서 참고, 톰캣 Libraries에서 servlet-api.jar 참고하길 바란다.)

즉 위의 동작 과정처럼 톰캣이 Http Servlet Request, Http Servlet Response 객체를 생성하고 우리가 그것을 처리하기 위해서는 톰캣이 구현해 놓은 HttpServlet을 상속받아 구현해야 한다는 것이다.

...

(이해가 되었다고 가정하에 계속 진행...)

...

자! 위의 방식대로 구현한다면 어떨까? 각 URL마다 Servlet을 만들어야 한다. 코드는 무한정 늘어날 것이다.

그래서 개선된 디자인 패턴이 FrontController패턴이다.

// web.xml
<servlet>
    <servlet-name>front</servlet-name>
    <servlet-class>com.test.FrontController</servlet-class>
</servlet>

<servlet-name>front</servlet-name>
<uri-pattern>*</uri-pattern>


// Controller
public class FrontController extends HttpServlet {
    HashMap<String, Controller> controllerUrls = null;
    
    @Override
    public void init(ServletConfig sc) throws ServletException {
        controllerUrls = new HashMap<String, Controller>();
        controllerUrls.put("/hello.do", new HelloController());
        controllerUrls.put("/car.do", new CarController());
    }
    
    public void service(HttpServletRequest request, HttpServletResponse response) {
        String uri = request.getRequestURI();
        Controller subController = controllerUrls.get(uri);
        subController.execute(request, response);
    }
}

개선된 방식이지만 이것도 결국 FrontController에 URL을 계속적으로 만들어야 한다. 유지보수 측면에서 너무나도 좋지 않다. 그래서 스프링이 이것을 대신해준다. DispatcherServlet!

// web.xml
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

web.xml을 구현해서 사용하고 있다면 위와 같을 것이다.

SpringBoot을 사용 중이시라면 아래와 같을 것이다.

@SpringBootApplication
public class SpringBootPjtApplication extends SpringBootServletInitializer {
    ...
}

DispatcherServlet은 Spring의 FrontController이라고 생각하면 편하다.

이제 아래의 그림과 같이 익숙하게 사용하는 MVC패턴이 그려질 것이다.

DispatcherServlet 구조

 

※ 예전 web.xml 흐름을 보니... Filter와 Interceptor가 보인다. 차이점을 간단하게 공부하자.

댓글