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에 대한 정보를 추출할 수 있게 하는 기술
- Web Application 내에 있는 모든 Servlet, JSP 간에
- 생성된 ServletContext 객체 추출 메소드
- ServletConfig의 getServletContext()
- HttpServlet의 getServletContext()
- HttpServlet 객체의 상위 클래스인 GenericServlet에서 ServletConfig를 상속받아 메소드 재정의하고 있음
Servlet Context의 Life Cycle
= Web Application의 Life Cycle
- 톰캣 구동
- Servlet Container 생성
- Web Application별 web.xml을 이용해
application마다 Servlet Context 초기화
하며 생성- Servlet을 실행할 때 최초의 요청이면
ServletConfig 객체가 생
성되며 init() 메소드의 인자값으로 전달 - Servlet Container가 시작될 때 웹서버에 등록된 웹 애플리케이션 단위로 하나의
ServletContext 객체
가 자동으로 생성
- Servlet을 실행할 때 최초의 요청이면
- 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를 초기화할 수 있음
- framework 레벨에서 직접 초기화할 수 있게 도와주는
Servlet 요청처리 단계
요청이 오면
Servlet Container는 web.xml 설정파일에 기록된 정보로
요청 URL에 해당하는 Servlet을 찾아 처리해 응답으로 보내줌
- web.xml
=> /hello
라는 요청을 보내면 HelloServlet이라는 서블릿을 찾아 처리한다고 기술되어 있음
동작
- 처음 클라이언트의 요청을 받은
웹서버(apache, nginx, haproxy 등) -> WAS Server의 웹서버(apache)
에 요청 전달 - (해당 요청이 동적 페이지 요청일 시)
WAS의 웹서버 -> Servlet Container
: HTTP 요청 전달 Servlet Container
HttpServletRequest, HttpServletResponse 객체
생성web.xml 설정파일
을 참고하여 매핑할 Servlet을 찾고- 요청 처리에 필요한
Servlet instance
가 Container에 존재하는지 확인
(Servlet instance의 생명주기를 Singleton으로 관리하는 역할을 수행) - 존재하지 않는다면 Servlet instance를 생성하고 해당 Servlet instance의
init()
호출하여 서블릿 인스턴스 초기화 Thread
생성service()
호출(request, response를 인자로) : 요청 처리
Servlet Container -> WAS의 웹서버
: 처리 결과 전달
HttpServletRequest / HttpServletResponse 객체 소멸
참고)
Servlet instance는 소멸되지 않음!
Servlet Container에서Servlet 객체는 Singleton
으로 관리되기 때문
다음에 같은 경로로 요청이 들어오면 객체를 생성하지 않고 해당 Servlet instance를 재사용
=> 하나의 Servlet instance를 재사용해 여러개의 HTTP 요청을 동시에 처리하므로 Servlet instance는 Thread-Safe하지 않음WAS의 웹서버 -> 웹서버(apache, nginx, haproxy 등)
: HTTP 응답 전달웹서버 -> 브라우저(클라이언트)
: 받은 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(선언문)
- 해당 JSP페이지에 대해 요청
- JSP-> Servlet Container : 해당 JSP페이지에 대한 Servlet instance 존재하는지 체크
- (존재하지 않다면) JSP컨테이너 : JSP페이지를 Servlet으로 변환해 컴파일하여 class파일 생성
(존재한다면) Servlet instance 바로 호출, service() 응답- Scriptlet에 작성된 소스 : 변환된 Servlet의 service()에 들어감
- Expression : 변환된 Servlet의 service()에서 out.println()로 변환
- Declaration에 작성된 소스 : 변환된 Servlet의 멤버메서드로 변환
- JSP에 작성된 일반 HTML 태그들 : 변환된 Servlet의 service() 안에서 out.write() 메서드로 변환
- 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