Apache

아파치 HTTP 서버는 아파치 소프트웨어 재단에서 관리하는 HTTP 웹 서버 소프트웨어

  • 웹 처음 등장 : 클라이언트의 요청 -> 정적인 데이터(HTML, 이미지 등)만 처리하는 웹서버뿐(Apache HTTP서버)
    • 한계 : 정적인 페이지만 보여줌 = 같은 HTTP요청에 대해서 항상 똑같은 페이지만 보여줌
  • 동적으로 페이지 보여주기 위해 등장한 기술 : CGI(Common Gateway Interface)


CGI

서버에서 다른 프로그램을 불러냄
-> 그 프로그램의 처리결과를 클라이언트로 보내주는는 인터페이스
-> 동적으로 페이지 보여줌
(기존의 웹서버 - 요청 받아 정보를 동적으로 생성해서 다시 클라이언트로 보내주는 것이 불가능했음)

  • CGI는 환경변수나 표준입출력을 다룰 수 있는 프로그램 언어(C, Java, PHP, Python 등)로 확장하여 이용 가능
  • 사용자가 데이터 입력해 요청 -> 해당 요청에 대한 CGI프로그램 동작 -> 표준 출력으로 돌려 보낸 내용을 그대로 응답으로 돌려줌


  • 요청이 들어올 때마다 CGI프로그램이 process 단위로 실행
    -> 웹 사용자가 많아짐에 따라 서버 부하 큼 -> 많은 사용자 처리 무리
  • 문제점 해결 : process 단위로 실행되던 것 -> Thread 단위로 실행되게끔 => Java Servlet!



Servlet

자바 기반, 데이터를 동적으로 처리하기 위한 Servlet 클래스의 구현 규칙을 지킨 프로그램

  • 각 요청에 대해 process를 생성해 처리하는게 아니라,
    process 1개가 있고 그 내부에 Thread Pool이라는 Thread들이 생성될 수 있는 공간을 만들어 Multi Thread로 처리
  • 내부적으로 CGI통신규약을 지켜 통신이 이루어짐
  • Servlet은 JSP, Spring Framework의 부모와도 같은 존재,
    자식인 JSP, Spring Framework는 내부적으로 Servlet 기술 사용


Servlet 코드

public class HelloServlet extends HttpServlet{

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
    PrintWriter writer = response.getWriter();
    writer.println("Hello");
  }
}

doGet() override
=> 클라이언트가 get방식으로 요청 -> service() 호출된 후 doGet() 호출
Servlet은 여러개의 자바파일 형태로 작성하며 각각의 Servlet에 요청 받을 URL을 매핑해주면 됨


Servlet Context

Servlet - Servlet Container 간 연동을 위해 생성되는 Context
Servlet Container와 통신하기 위해서 사용되는 메소드를 지원하는 인터페이스

  • Web Application 단위로 정보를 Server쪽에 유지할 수 있는 방법 : ServletContext 객체 사용
    = 동일한 Web Application에 존재하는 Servlet들은 동일한 ServletContext 객체 사용
    • Web Application 내에 있는 모든 Servlet, JSP 간에 정보 공유가능
    • Servlet Container에 대한 정보를 추출할 수 있게 하는 기술
  • 생성된 ServletContext 객체 추출 메소드
    • ServletConfig의 getServletContext()
    • HttpServlet의 getServletContext()
      • HttpServlet 객체의 상위 클래스인 GenericServlet에서 ServletConfig를 상속받아 메소드 재정의하고 있음


Servlet Context의 Life Cycle
= Web Application의 Life Cycle

  1. 톰캣 구동
  2. Servlet Container 생성
  3. Web Application별 web.xml을 이용해 application마다 Servlet Context 초기화하며 생성
    1. Servlet을 실행할 때 최초의 요청이면 ServletConfig 객체가 생성되며 init() 메소드의 인자값으로 전달
    2. Servlet Container가 시작될 때 웹서버에 등록된 웹 애플리케이션 단위로 하나의 ServletContext 객체가 자동으로 생성
  4. Servlet Container가 종료되면 소멸


Web Application 단위 정보 공유

  • 여러 페이지 간에 데이터를 공유하기 위해 사용하는 메소드
    • void setAttribute(String name, Object value) : 웹 애플리케이션 범위에서 공유할 데이터를 ServletContext 객체에 등록
    • Object getAttribute(String name) : ServletContext 객체에 등록한 데이터를 추출
    • void removeAttribute(String name) : ServletContext 객체에 setAttribute() 메소드로 등록한 데이터 삭제


Servlet Life Cycle

1. init()

  • Servlet을 처음 메모리에 올릴때 실행
  • Servlet을 초기화하며 처음에 한번만 실행

2. service()

  • 요청/응답(request/response)을 처리
    • 요청이 GET인지 POST인지 구분하여 doGet() 또는 doPost()로 분기

3. destroy()

  • Servlet 종료요청이 있을때 destroy() 실행



Apache Tomcat

자바 서블릿이 실행될 수 있는 Web Container(Servlet Container) 환경을 제공하는 Web Application Server

  • Apache 웹서버의 일부 기능 + Web Container 조합
    • 웹서버의 정적 데이터 처리 기능과 동적 데이터 처리 기능 모두 포함
    • 일반적인 웹서버와는 다르게 DB연결, 다른 응용프로그램과 상호 작용 등 동적인 기능 사용가능
  • 하나의 Tomcat은 하나의 JVM을 가지고 있음


Tomcat 구조

제목 없음

  • Servlet은 Web Application Server 안에서 구동
  • 하나의 Tomcat Server, 여러 개의 Web Application 배포하여 운영 가능
    • 각각의 Web Application은 별도의 Servlet Context 가짐
    • 사용자는 같은 Tomcat에 배포되는 application이라도 session은 별도로 할당받음


web.xml

배포 기술자 파일
Servlet이나 Filter 등을 작성해 Web Application의 환경을 설정

  • Servlet Container(Tomcat 등)에 application 배포하는 방법을 설명
  • Servlet Context를 초기화하기 위해 사용


  • Tomcat은 web.xml 설정파일을 통해 해당 Web Application의 Servlet Context를 초기화하며 Servlet에 대한 정보를 읽음
    • 배포할 Servlet이 무엇인지, Servlet 매핑 경로는 무엇인지 등


Tomcat에 Web Application 추가하는 방법

예전 방식(Tomcat 4.x이하)
톰캣 서버 실행~
1. server.xml 읽음 : 서비스해줘야할 프로젝트를 확인

  • 가장 하단부 Context 엘리먼트에 docBase, path와 source에 프로젝트명이 적혀져 있음
  • WAS는 Web Application을 Context로 인식 - path 경로로 요청 전달해주어야할 프로젝트 확인
<Context docBase="myWeb" path="/web" reloadable="true" source="org.eclipse.jst.jee.server:webTest"/>

2. web.xml 읽음 : Web Application의 환경설정 확인


요즘 방식(Tomcat 4.x 이상)
Web Application의 폴더구조만 가지고 있으면 자동으로 설정됨

  • webapp 디렉토리 아래에 넣어주기
    • webapp/WEB-INF 디렉토리 아래에 web.xml 위치
      -> http://localhost/어플리케이션명으로 접근이 가능


  • 서블릿3.0버전이후부터 web.xml 없이도 Servlet Context 초기화 작업 가능
    • framework 레벨에서 직접 초기화할 수 있게 도와주는 ServletContainerInitializer API를 제공하기 때문
    • ServletContainerInitializer 인터페이스 구현체를 만들면
      Servlet Container는 해당 클래스의 onStartUp 메서드 영역을 호출하여 Web Application의 Servlet Contex를 초기화할 수 있음

제목 없음



Servlet 요청처리 단계

요청이 오면
Servlet Container는 web.xml 설정파일에 기록된 정보로
요청 URL에 해당하는 Servlet을 찾아 처리해 응답으로 보내줌

  • web.xml

제목 없음

=> /hello라는 요청을 보내면 HelloServlet이라는 서블릿을 찾아 처리한다고 기술되어 있음


제목 없음

제목 없음

제목 없음

동작

  1. 처음 클라이언트의 요청을 받은 웹서버(apache, nginx, haproxy 등) -> WAS Server의 웹서버(apache)에 요청 전달
  2. (해당 요청이 동적 페이지 요청일 시) WAS의 웹서버 -> Servlet Container : HTTP 요청 전달
  3. Servlet Container
    1. HttpServletRequest, HttpServletResponse 객체 생성
    2. web.xml 설정파일을 참고하여 매핑할 Servlet을 찾고
    3. 요청 처리에 필요한 Servlet instance가 Container에 존재하는지 확인
      (Servlet instance의 생명주기를 Singleton으로 관리하는 역할을 수행)
    4. 존재하지 않는다면 Servlet instance를 생성하고 해당 Servlet instance의 init() 호출하여 서블릿 인스턴스 초기화
    5. Thread 생성
    6. service() 호출(request, response를 인자로) : 요청 처리
  4. Servlet Container -> WAS의 웹서버 : 처리 결과 전달
    HttpServletRequest / HttpServletResponse 객체 소멸
    참고)
    Servlet instance는 소멸되지 않음!
    Servlet Container에서 Servlet 객체는 Singleton으로 관리되기 때문
    다음에 같은 경로로 요청이 들어오면 객체를 생성하지 않고 해당 Servlet instance를 재사용
    => 하나의 Servlet instance를 재사용해 여러개의 HTTP 요청을 동시에 처리하므로 Servlet instance는 Thread-Safe하지 않음
  5. WAS의 웹서버 -> 웹서버(apache, nginx, haproxy 등) : HTTP 응답 전달
  6. 웹서버 -> 브라우저(클라이언트) : 받은 HTTP 응답을 전달


Servlet Container & IoC

제목 없음

  • Servlet Container : Servlet instance를 Singleton으로 생명주기 관리
  • Servlet은 클라이언트로부터 요청이 들어올 때마다 각 요청에 대해 Thread를 생성하여 Multi Thread로 처리가 이루어짐


=> Servlet은 전통적으로 개발자가 주도하던 객체생성 및 소멸 등의 프로그램 흐름 제어를 Servlet Container가 주도
-> 제어권이 반전(역전)되었다! 해서 제어의 역전(IoC, Inversion of Control)이라 함 (IoC개념은 Servlet에서부터 존재..!)


Servlet의 lazy-loading & pre-loading

  • lazy-loading 방식 : 해당 Servlet에 대한 클라이언트의 최초 요청을 받을 때 해당 Servlet instance를 생성하여 Singleton으로 활용(지금까지 설명한 것)
    • 단점: 최초요청 시 지연시간 발생
  • pre-loading 방식 : 서블릿 컨텍스트를 초기화하는 시점에 미리 서블릿 인스턴스를 생성(단점해결)
    • 방법: web.xml의 해당 서블릿 영역에 load-on-startup 옵션 주어야함



JSP

Servlet은 자바 코드 안에 HTML코드를 프린트해 출력하는 형태
너무 번거로움 => JSP 등장

  • JSP는 서블릿과 반대로 HTML코드 안에 자바코드를 삽입하는 형태
    -> view를 구현하는데 훨씬 편리
  • JSP와 서블릿은 완전히 다른 개념이 아님
    • JSP코드는 결국 서블릿으로 변환과정 필요


JSP -> Servlet 변환

제목 없음

  • JSP 스크립트 요소 : Scriptlet(스크립트릿), Expression(표현식), Declaration(선언문)
  1. 해당 JSP페이지에 대해 요청
  2. JSP-> Servlet Container : 해당 JSP페이지에 대한 Servlet instance 존재하는지 체크
  3. (존재하지 않다면) JSP컨테이너 : JSP페이지를 Servlet으로 변환해 컴파일하여 class파일 생성
    (존재한다면) Servlet instance 바로 호출, service() 응답
    1. Scriptlet에 작성된 소스 : 변환된 Servlet의 service()에 들어감
    2. Expression : 변환된 Servlet의 service()에서 out.println()로 변환
    3. Declaration에 작성된 소스 : 변환된 Servlet의 멤버메서드로 변환
    4. JSP에 작성된 일반 HTML 태그들 : 변환된 Servlet의 service() 안에서 out.write() 메서드로 변환
    5. page 디렉티브의 속성값들 : Servlet으로 변환시 참고할 정보로 활용


JSP 컨테이너 : JSP 파일을 Servlet으로 변환 및 컴파일까지만 담당하는 프로그램
변환된 Servlet의 수행은 Servlet Container가 담당
(Servlet Container에 해당 요청에 대한 Servlet 객체가 존재하므로 위의 Servlet 요청처리 과정을 거침)


=> Servlet과 JSP의 불편함(Business Logic과 View를 한 곳에서 처리함)을 해소하기 위해 Spring MVC(JSP는 로직 처리가 없이 단순히 Client에게 보여지는 뷰만을 담당 등) 탄생



Reference
https://velog.io/@suhongkim98/CGI%EC%99%80-%EC%84%9C%EB%B8%94%EB%A6%BF-JSP%EC%9D%98-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
https://float.tistory.com/156
https://www.youtube.com/watch?v=2pBsXI01J6M&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
https://jordy-torvalds.tistory.com/14
https://kgvovc.tistory.com/38

업데이트: