도찐개찐

[JAVA] 서블릿 처리구조 본문

JAVA

[JAVA] 서블릿 처리구조

도개진 2022. 7. 8. 15:35

웹 서버의 주된 기능은 웹 페이지를 클라이언트로 전달하는 것입니다. 주로 그림, CSS, 자바스크립트를 포함한 HTML 문서가 클라이언트로 전달됩니다. 하지만 이런 웹 서버의 경우 이미 존재하는 즉, 정적인 페이지를 제공하는 역할만 할 수 있습니다. 실시간으로 작성된 페이지를 제공하거나 서버 상에 데이터를 저장하는 것은 웹 서버가 할 수 없는 일입니다. 때문에 이런 역할을 해 주는 다른 도우미 애플리케이션이 필요합니다.

 

이런 도우미 애플리케이션을 사용하면 웹 서버는 도우미 애플리케이션에 요청을 전달하기만 합니다. 그러면 도우미 애플리케이션은 요청받은 작업을 수행하거나 정적인 페이지를 만들어서 웹서버로 전달합니다. 웹서버는 이를 다시 클라이언트로 전해줍니다.

 

자바에서는 이 역할을 해 주는 것이 서블릿입니다.

 

그러나 서블릿은 도움이 필요합니다. 요청이 들어오면 누군가 요청을 처리할 새로운 스레드를 만들어야 하고 서블릿에서 필요한 메서드를 호출해야 합니다. 또 파라미터로 받은 값을 넘겨주기도 해야 합니다. 이 역할을 하는 것이 바로 컨테이너 입니다.

 

웹서버가 사용자로부터 서블릿에 대한 요청을 받으면 컨테이너에게 이 요청을 넘깁니다. 요청을 넘겨받은 컨테이너는 서블릿을 찾아 필요한 메소드를 호출하게 됩니다.

 

컨테이는 사용자로부터 요청을 받을 때 마다 요청을 처리할 스레드를 생성합니다. 그리고 그 스레드에서 필요한 서블릿 메소드를 호출하게 되는 것입니다. 그렇다고 해서 스레드를 무제한으로 생성하기만 하는 것은 아니고 컨테이너 내부에 스레드풀(Thread pool)에 스레드를 저장하고, 필요할 때 꺼내 사용하게 됩니다.

 

여기서 유의해야 할 점은 요청이 올 때 마다 스레드를 새로 생성하거나 스레드 풀에서 꺼내 쓰는 것이지 서블릿 인스턴스를 새로 생성하는 것은 아니라는 것입니다.

 

컨테이너의 동작 방식을 살펴 보겠습니다.

 

  1. 사용자(클라이언트)가 URL을 통해 요청을 보내면 HTTP Request를 Servlet Conatiner로 전송합니다.
  2. HTTP Request를 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체를 생성합니다.
  3. (web.xml은 사용자가) 그 다음에는 요청한 URL을 분석하여 어느 서블릿에 대해 요청을 한 것인지 찾습니다.
  4. 해당 서블릿에서 service메소드를 호출한 후 POST, GET여부에 따라 doGet() 또는 doPost()를 호출합니다.
  5. doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse객체에 응답을 보냅니다.
  6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킵니다.

 

여기서 HttpServletRequest, HttpServletResponse 객체를 생성한 컨테이너는 요청에 알맞은 서블릿을 찾게 되는데 이 서블릿을 찾기 위해서는 개발자가 서블릿을 매핑해줘야 합니다. 그렇지 않으면 적절한 서블릿을 찾을 수 있는 정보가 없기때문에 컨테이너는 서블릿을 찾지 못하게 됩니다.

 

이 서블릿 매핑 방법은 몇 가지가 있는데 가장 많이 쓰이는 것은 배포서술자(Deployment Descriptor)를 사용하거나 어노테이션을 이용하는 매핑 방법입니다.

 

먼저 배포서술자를 사용한 방법을 알아보도록 하겠습니다.

 

web.xml 파일을 만들고 web-app 태그 내부에 서블릿을 정의합니다. <servlet> 태그 안에 등록된 서블릿들이 컨테이너가 관리하는 서블릿을 의미합니다. 이 때 사용하는 <servlet-name>은 오로지 배포서술자 안에서 구분을 위해서 사용하는 이름으로 실제 클래스명이나 클라이언트에서 호출한 URL 이름과는 다릅니다. 그리고 클래스의 위치를 이름과 매핑합니다.

 

servlet-mapping 태그를 통해 클라이언트에서 URL을 통해 요청받은 이름과 servlet-name을 매핑합니다. 이 때 URL은 클라이언트 에서 사용하는 서블릿의 이름으로 실제 클래스 이름과는 다릅니다.

 

 

이렇게 배포서술자를 이용하면 하나의 서블릿이 세가지의 이름을 가지게 됩니다. 이렇게 함으로서 유연성, 보안성이 증대되는 효과를 얻을 수 있습니다. 클래스의 위치나 이름이 바뀌었을 때 배포서술자의 해당 부분만 바꿔 주면 쉽게 수정할 수 있고, 클라이언트에 실제 클래스 위치를 숨겨 주기 때문에 보안성이 증대된다고 볼 수 있습니다.

 

단순히 서블릿을 매핑하는 용도 외에도 배포서술자를 통해 웹 앱에 필요한 다양한 정보를 서술할 수 있습니다. 배포서술자를 활용했을 때 가장 큰 장점은 작성한 소스코드를 바꾸지 않고 중요한 부분을 수정할 수 있다는 점입니다.

 

 

서블릿 초기 표준에는 이 배포서술자가 반드시 필요 했지만 servlet 3.0 부터는 Annotation을 지원하게 되면서 배포서술자 없이도 서블릿 매핑이 가능해 지게 되었습니다. 해당하는 클래스 위에 이런 어노테이션을 달아주는 것 만으로도 쉽게 매핑이 가능합니다. 어노테이션의 장점은 역시 편의성입니다. 한줄의 코드로 매핑을 할 수 있기 때문에 복잡한 배포서술자의 xml 태그를 거치지 않아도 됩니다.

 

그럼 이제 실제 서블릿 코드를 만나보겠습니다.

 

클래스 위에 어노테이션을 이용해서 URL 매핑을 완료했고 HttpServlet 클래스를 상속받은 클래스를 만들고 여기서는 doGet() 메소드를 오버라이드 했습니다.

 

컨테이너에서 만들어진 HttpServletRequest, HttpServletResponse객체를 파라미터 값으로 받아 온 것을 볼 수 있습니다.

 

그리고 response 객체에 html 코드를 씁니다. 그러면 컨테이너가 클라이언트로 html 코드를 포함한 응답 메세지를 보내게 됩니다.

 

그런데 out.println() 으로 HTML 코드를 생성하는 것은 작성하기도 불편하고 가독성이 떨어집니다. 그리고 오류가 발생했을 때나 새로운 요구사항이 추가 되었을 때 수정을 하기도 어려울 수 밖에 없습니다. 자바 코드 안에서 HTML 태그를 넣는것이 아니라 반대로 HTML 안에 자바 코드를 넣을 수 있다면 이런 문제들이 해결될 수 있을 것입니다. 그 역할을 해 주는 것이 바로 JSP 입니다.

 

출처 : https://webfirewood.tistory.com/38

728x90
Comments