본문 바로가기

컴퓨터공학/Spring framework 분석

개념> Servlet Container

Container

스프링 핵심 작동 방식은 개발자가 직접 오브젝트를 생성, 호출이 아니라 

Spring Container를 통해 관리되는 인스턴스 Bean으로 관리. 
Bean을 만들기 위해 설정 정보가 필요, 설정 정보는 IOC 컨테이너가 필요로 하는 설정 메타 정보.
다시 말해서 Bean을 어떻게 생성하고 동작할 것인가에 관한 정보.
Bean 설정 정보는 BeanDefinition 인터페이스로 표현. 
IOC 컨테이너는 BeanDefinition 으로 만들어진 메타 데이터를 가진 오브젝트를 사용하여 IOC와 DI 작업. 
IOC 는 Bean 메타 정보를 바탕으로 Bean Object를 생성
프로퍼티나 생성자로 의존 오브젝트를 주입하는 DI 작업 수행
따라서 Spring Container 에서 인스턴스를 관리하기 위해 각 오브젝트는 다음 규칙 준수
1. 기본 생성자를 갖고 있어야 함
2. 필드는 private 선언해야 함
3. getter/setter 메서드 갖고 있어야 함
Spring Container는 DI Container 또는 IOC Container 라고 부름

 

Spring-framework-Chinese documentation 1: IOC container, introducing Spring IoC container and bean - Programmer All

 

Spring-framework-Chinese documentation 1: IOC container, introducing Spring IoC container and bean - Programmer All

5.1 Introduction Spring IoC Container and Bean 5.2 Container Overview This chapter introduces the Spring Framework implementation control reversal (IOC)principle.IOC is also known asDependency injection(DI)。It is a process that defines their dependen

www.programmerall.com


Servlet Container

 

 

WAS는 다양한 종류의 컨테이너를 내장하고 있다.

이 중에서 서블릿 관련 기능만 있는 것을 서블릿 컨테이너라고 부른다.

이 외에도 JSP Container, EJB Container 등이 있다.

Servlet Container는 Servlet instance를 생성하고 관리한다. 

 

앞에서 했던 Listener와 DispatcherServlet은 ServletContainer 안에 있다.

 

 

 

<< Web server와 WAS의 작용 >>

1. Web Browser에서 Web Server에 HttpRequest를 보내면 Web Server는 WAS의 Web Server에 전달
2. WAS Server의 Web Server는 HTTP 요청을 Servlet container에 전달
3. Servlet container는 HTTP 요청에 필요한 servlet 인스턴스가 힙 메모리 영역에 있는지 확인.
존재하지 않으면 생성하고 해당 Servlet instance의 init( ) method를 호출하여 Servlet instance를 초기화.
4. Servlet container는 servlet instance의 service 메소드를 호출하여 HTTP 요청 처리. 
WAS Server의 Web Server에게 처리 결과를 전달.
5. WAS Server의 Web Server는 HTTP 응답을 Web Server에 전달.
Web server는 받은 HTTP 응답을 Web Browser에 전달

 

 

<< Apache와 Tomcat의 차이점 >>
Web server와 Web application server(WAS) 분리
<Web server>
Web server는 HTML 문서나 각종리소스를 전달하는 소프트웨어
해당 소프트웨어를 실행하는 하드웨어 또한 Web server이다.  아파치 Http server, NGINX, WebtoB 같은 것들.
Web server의 할 일은 Client가 HTTP 규격에 따라 요청을 보내면 서버는 해석하고 맞는 데이터를 보낸다. 
요청, 매칭, HTTP에 맞게 응답. 이것을 Static Web Server라고 한다. 
동적 기능 수행을 위해 Web Application Server 사용

 

<Tomcat>
Web application sever는 동적 컨텐츠를 제공하기 위해 만들어진 application server로 
웹 프로그램을 실행할 수 있는 환경을 제공한다. 흔히 아는 Tomcat이다. 
정확히 말하면 ServletContainer가 Tomcat이다.
ServletContainer인 Tomcat은 자바 프로그램이기 때문에 하나의 JVM이 붙는다.
one WAS per one JVM
1. 동적과 정척 처리 분리
2. 보안성
( 더 자세한 was와 웹서버 분리 이유
https://lilo.tistory.com/57 )

 

 

<<동적과 정적은 대체 무슨 뜻일까?>>
정적은 저장된 그대로 파일을 보는 것
동적은 그런 내용을 다른 변수에 의해 변경되어 보이는 것
예를 들어 인터넷 뉴스나 웹툰이나 이런 것들을 볼 때는 정적 페이지
쇼핑몰에서 상품 등록, 제거, 회원 관리, 상품 재고관리할 때 무수히 많은 페이지를 정적으로 처리하려면 일일히 만들어야 한다. 
하지만 그럴 필요 없이 동적페이지는 스크립트로 상품 등록 및 관리, 회원 가입 스크립트를 작성하고 생성하면 모든 페이지를 일일이 만들 필요없다.  
( 동적과 정적의 차이점
https://titus94.tistory.com/4 )

 

 

복습하면 WAS 는 일부 Web server와 Web Container로 구성.
앞단의 Web server는 HTTP 요청을 받아 Web Container로 넘긴다.
Web Container는 로직 처리 후 데이터를 만들어서 Web Server에 넘긴다.
Servlet Container인 Tomcat은 요청을 받으면 Tomcat engine이 요청에 맞는 Context를 찾고 해당 Context는 본인의 web.xml에 맞는 바탕으로 전달받은 요청을 Servlet 에 전달하여 처리한다. 

 

 

 

<< tomcat의 web.xml 설정 >>


web application에서 servlet container도 있고 spring container도 있고 여러 가지가 있는데  
톰캣은 servlet container이고, web.xml은 servlet container의 환경설정 파일.
프로젝트 src 폴더에서 webapp -> WEB-INF에 있다.
이클립스에서 프로젝트가 web application이라는 거 알 수 있다.
web.xml은 servlet container인 톰캣에 있는 모든 servlet의 기본 설정을 정의한다.
경로 위치는 %CATALINA_HOME%\confg\web.xml에 있다.
톰캣에 담을 수 있는 servlet은 
defaultServlet, invokerServlet, JspServlet 이 있으니 web.xml에 작성할 수 있고
servlet mapping을 써서 매핑 설정을 하거나 세션기간, 시작 페이지를 설정할 수 있다. 

( 톰캣 web.xml 설명
노트 :: 톰캣 web.xml 설명 (tistory.com)

 

톰캣 web.xml 설명

▣ web.xml 파일이란? 1. 톰캣의 실행환경에 대한 정보를 담당하는 '환경설정' 파일 이다. 2.  각종 servlet의 설정과 servlet 매핑, 필터, 인코딩 등을 담당한다. 3. web.xml은 톰캣에 있는 모든 web applicatio.

jinwoonote.tistory.com

 

 

 

 


Servlet

Servlet API는 크게 4개로 본다.

Servlet, Sharing Information, Filter, Listener 

 

 

Servlet이란 Java EE 표준 중 하나라 javax.servlet.Package를 기반으로 Server에서 동작하는 Class를 의미한다. 

대부분 웹 서블릿은 javax.servlet.http.HttpServlet을 상속받아 구현한다. 

최상위 javax.servelt.Servlet 인터페이스의 init( ), service( ), destroy( ) method는 Servlet container가 호출

우리는 HttpServlet method를 override해서 정의하면 요청에 대한 처리를 할 수 있다. 

init( ), service( ), destory( ) 3개 method를 반드시 정의해야 한다. 

init( ) : Servlet 생성 시 호출

service( ) : Servlet으로 요청이 전달될 때마다 호출, 실제 Servcie Logic을 수행,

destroy( ) : Servlet이 삭제될 때 호출

 

 

 

javax.servlet.Servlet 인터페이스

모든 서블릿은 다섯 가지 메소드를 가져야 한다. 이 중에서 3개는 생명주기 메소드이다. 

service(ServletRequest, ServletResponse)

init(ServletConfig)

destroy( )

getSetvletConfig( )

getServletInfo( )

 

javax.servlet.GenericServlet 클래스

: 추상클래스로 대부분 필요한 servlet 메소드를 구현했다. 여기에 servlet 인터페이스에 정의된 것도 있다.

service(ServletRequest, ServletResponse)

init(ServletConfig)

init( )

destroy( )

getServletConfig( )

getServletInfo( )

getInitParameter(String)

getInitParameterNames( )

getServletContext( )

log(String)

log(String, Throwable)

 

javax.servlet.http.HttpServlet 클래스

: HttpServlet 클래스도 추상 클래스.

Http 측면을 반영하기 위해 service( ) 를 재정의.

service( ) 메소드는 오직 HTTP Request와 Response를 받는다.

다른 Request와 Response는 받지 않는다.

 

service(HttpServletRequest, HttpServletResponse)
service(ServletRequest, ServletResponse)
doGet(HttpServletRequest, HttpServletResponse)
doPost(HttpServletRequest, HttpServletResponse)
doHead(HttpServletRequest, HttpServletResponse)
doOptions(HttpServletRequest, HttpServletResponse)
doPut(HttpServletRequest, HttpServletResponse)
doTrace(HttpServletRequest, HttpServletResponse)
doDelete(HttpServletRequest, HttpServletResponse)
getLastModified(HttpServletRequest)

 

service 메소드에서 클라이언트 HTTP 메소드(GET, POST 등등) 참조하여

doGet을 호출할 지? doPost를 호출할 지 판단.

따라서 service 재정의할 필요 없이 doGet, doPost를 재정의하면 된다.

 

서블릿 초기화 코드가 있으면 init( )을 재정의하면 된다. 데이터베이스 접속이라든가.

필요한 내용은 doGet이나 doPost나 다른 메소드에 작성.

만약 doPost를 재정의하지 않으면 서블릿 컨테이너는 생각한다.

이 서블릿은 HTTP POST를 지원하지 않는구나 라고.

 

 

Java - 서블릿의 일생 (silverwolf.co.kr)

 

Java - 서블릿의 일생

컨테이너가 관리하는 서블릿사용자가 서블릿에 대한 링크(URL)를 클릭합니다.컨테이너는 요청된 Request가 서블릿이라는 것을 간파하고는 다음 두 개의 객체를 생성합니다.HttpServletResponseHttpServletR

www.silverwolf.co.kr


웹서버에서 서블릿은 

1. Socket 생성 2. InputOutputStream 생성을 개발자 대신 진행.
Container는 Servlet 의 life cycle을 관리.
매번 요청이 드러오면 새로운 Thread를 요청 별로 부여.
즉, 컨테이너는 하나의 Servlet에 오는 여러 요청을 진행하기 위해 여러 Thread를 작동. 

 

서블렛 인스턴스는 하나만 만들어 지고 스레드가 이걸 공유하여 쓴다.

모두가 쓰고 있는데 Servlet instance의 변수가 바뀐다면??

Thread safe하지 않게 된다.  따라서  doGet이나 doPost 메소드의 지역변수에 변수를 이용한다.  

 

서블릿의 다른 종류로

InvokerServlet 

: web.xml에 정의하지 않는 어떤 Servlet도 실행하게 한다.

기본적으로 "/servlet/*"  의 URL에 매핑.

톰캣 버전이 올라가면서 보안때문에 기본값은 실행하지 못하게 설정되어있음 (주석처리)

 

JspServlet 

: JSP 컴파일과 실행을 담당하는 Servlet


Servlet Config 

Serlvet confguration 오브젝트는 servlet container가 servlet을 초기화할 때 정보를 전달하기 위해 사용된다.

Servlet Config 인터페이스 메소드는 다음으로 구성

getServletName( )

: Servlet이름 반환

getServletContext( )

: ServletContext 반환

getInitParameter(String)

: 입력값에 해당하는 Parameter 정보 반환. Parameter가 없으면 null 반환

getInitParameterNames( )

: Servlet이 가지고 있는 초기 Parameter Enumeration 반환.

존재 Parameter가 없으면 Empty Enumeration 반환


Servlet Context

Servlet이 Servlet Container와 소통하기 위해 사용되는 메서드 모둠을 정의

MIME 종류 파일을 얻거나 요청을 주거나, 또는 

 

 


Scope


IOC Container는 Singletone Scope로 하나의 인스턴스를 생성하고 관리 
Singleton Scope에서 주의점은 하나의 Bean 오브젝트가 동시에 여러 스레드가 접근하므로

상태 값을 인스턴스 변수에 저장하면 안된다. 

하나의 프로세스에서 여러 스레드가 작업을 동시에 수행하는 것을 멀티 스레드라고 한다.
만약 서버가 싱글 스레드 환경이라면, client가 요청할 때 최초 요청한 사용자에 응답을 보내기 전까지

다른 사용자들은 서비스를 이용 불가능.
따라서 대다수 웹 서버는 멀티 스레드를 이용한다. 
대표 싱글 스레드 방식 웹 서버 : Node.js


멀티 스레드 환경에서 요청이 있을 때마다 Thread 생성하고 해당 요청을 처리
요청하는 Client 수가 많아지면 그만큼 Thread 생성/수거 비용 및 오버헤드가 발생
문제 개선을 위해 Thread pool 사용한다.
Thread pool 이란 Thread를 미리 만들어 둬서 요청이 오는 즉시 처리하는 기능
Thread 생성/수거 비용 및 오버헤드 단점을 개선과 Thread 재사용이 가능하다는 장점이 있지만
적절히 pool을 유지하지 않으면 메모리 낭비. 

Thread-safe 
어떤 함수가 한 스레드로부터 호출되어 실행 중일 때, 다른 스레드가 그 함수를 호출하여 동시 사용해도 

각 스레드 함수 수행 결과가 올바르게 나온다.

Singletone pattern인 이유
요청할때마다 멀티스레드로 생성된 많은 Thread가 객체를 생성할 것이다. 

그러면 성능저하와 메모리 저하 발생.
따라서 싱글턴 객체로 생성해서 모든 Thread가 공유할 수 있게 설계.
Tread의 특징은 지역 변수를 저장하는 Stack 영역은 Thread 별로 할당, 

전역변수를 저장하는 Heap 영역과 Code, Data 영역은 공유.
싱글턴 패턴으로 공유되는 객체가 가변 객체라면 Thread safe하지 않다. 

따라서 Bean 객체는 불변 객체로 활용. 
@Controller, @Service, @Repository, @Component 등등 어노테이션이 달린 객체에서 전역변수는 불변 객체. 
가변객체는 VO, DTO, Map 과 같은 객체이다. 
Thread는 메소드를 호출하여 로직 내용만 공유해서 사용하면 되니 동기화할 필요없고 많은 요청이 와도 괜찮다.

 

Each request runs in a separate thread! - Head First Servlets and JSP, 2nd Edition [Book] (oreilly.com)

 

Head First Servlets and JSP, 2nd Edition

Each request runs in a separate thread! You might hear people say things like, “Each instance of the servlet...” but that’s just wrong. There aren’t multiple instances of any … - Selection from Head First Servlets and JSP, 2nd Edition [Book]

www.oreilly.com


Servlet Container, Servlet, Thread

 

 

1. 요청이 오면 container가 처리한다.  두 개의 객체를 생성한다. HttpServletResponse, HttpServletRequest 

2. 컨테이너는 web.xml을 확인하여 요청 URL을 분석하여 어떤 servlet에 해당하는지 파악.

servlet 스레드 생성.

3. 컨테이너는 서블릿 호출(service()).

4. 호출된 서블릿 작업을 담당한 스레드는 요청에 따라서 doPost, doGet 호출.

브라우저에서 지정한 방식에 따라서 doGet( )인 지, doPost( )인 지 결정.

만약 클라이언트가 HTTP GET 메소드를 날렸으면 service( ) 는 servlet의 doGet( )을 호출.

5. 호출된 doPost 또는 doGet 메소드는 생성된 동적페이지를 Response객체에 실어서 컨테이너에게 전달 

6. 컨테이너는 전달받은 Response 객체를 HTTPResponse 형태로 전환하여 웹서버에 전달하고 생서한 스레드를 종료하고 httpServletRequest 및 httpServletResponse 객체 소멸

 

 

 

JVM의 역할
JVM이 각 요청을 분리된 자바 스레드 내부에서 처리.
서블릿은 HTTP 요청에 응답하는 자바 클래스. 그 내용을 스레드에서 동작. 
요청이 들어오면 서블릿 컨테이너에서 서블릿에게 전달하고, 
JVM이 해당 요청을 처리한 다음 결과를 동적으로 반환하는 것.

 

 

 

Servlet container는 세 가지 기능이 있다.

1. 생명 주기 관리 :

서블릿을 로드해 초기화,

클라이언트 요청으로 서블릿 메소드 호츨,

서블릿 컨테이너가 종료되면 서블릿 종료시키고 메모리 정리 destroy

서블릿의 탄생과 죽음을 관리

 

2. 통신 지원 :

웹서버에서 오는 요청을 분석해 서블릿에서 실행할 수 있도록 도와준다.

서블릿에서 웹서버 정보 확인할 수 있도록 통신을 도와줌.

소켓을 만들고 listen, accept 등을 API로 제공하여 복잡한 과정을 생략할 수 있게 해준다.

 

3. 멀티스레딩 지원 :

클라이언트 요청이 오면 서블릿 생성, 

이미 생성된 서블릿 요청은 스레드를 생성해 실행한다. 

HTTP 서비스 메소드를 실행하면 스레드는 자동 소멸.

 

4. 보안 관리:

서블릿 컨테이너를 사용하면 보안 내용 서블릿이나 자바 클래스 구현 안해도 됨

보안관리는 XML 배포 서술자에 기록.

보안 내용에 수정 사항이 생겨도 자바 소스 코드를 수정하거나 다시 컴파일하지 않아도 됨.

 

 

배포서술자?

web.xml 같은 것. Deployment Descriptor

웹 어플리케이션에서 서블릿 클래스를 사용하려면 서블릿을 등록하는 과정이 필요. 

서블릿 클래스를 등록하는 곳을 배포서술자라고한다. 

배포서술자 장점

1. 웹 어플리케이션 배포 정보를 제공하므로 서로 다른 컨테이너에서도 동일한 어플리케이션 운영 가능

2. 특정 서블릿 또는 전체 어플리케이션에서 공유 가능한 초기화 파라미터 설정 가능하므로 데이터 공유 용이

3. 서비스 운영 중 프로그램을 수정하지 않아도 어플리케이션 동작에 대한 조정이 가능 

 

 

[JSP & Servlet 배경지식] 2. WS & WAS / Container | Opendocs

 

[JSP & Servlet 배경지식] 2. WS & WAS / Container | Opendocs

1. Web Server & Web Application Server > 동적웹페이지를 서비스 하기 위해서는  WAS(웹 어플리케이션 서버)가 필요하다. 하지만 정의하는 기준에 따라 다르게 어떤건 WAS가 아니라고 하는 경우가 있지만

myblog.opendocs.co.kr

 

web.xml 파일과 배포서술자(Deployment Descritor) (tistory.com)

 

web.xml 파일과 배포서술자(Deployment Descritor)

web.xml 이란? web.xml 파일은 웹 어플리케이션을 구성하는 웹 컴포넌트에 대한 구성 및 배치 정보를 제공하며, 웹 어플리케이션의 배포서술자(Deployment Descriptor ; DD) 역할을 하는 XML 형식의 파일이다

wanna-b.tistory.com

서블릿 컨테이너(Servlet Container) 란? (velog.io)

 

서블릿 컨테이너(Servlet Container) 란?

서블릿들을 위한 상자(Container) 입니다.

velog.io


하나의 클라이언트 당 하나의 thread(Thread per connection) 아니라 요청 당 하나의 thread(Tread per request)
누가 보냈는지 신경 안 쓴다. 
그렇다면 왜 Thread per request를 사용하는 걸까?
연결하는 동안 thread가 유지하면 요청이 있을 때까지 thread는 idle 상태로 있어야 하고 
thread 갯수 한도가 넘어가면 새로운 연결은 못해서 다른 사람은 대기해야 한다.
therad per request를 사용하면 진행할 때만 thread를 쓰니까 수 만명이 사용하더라도 현재 사용 중인 요청만 투입하면 된다.

 

 

 


 

Filter 

javax.servlet.Filter 

필터를 이용한 디자인 사례는 다음과 같다.

1. Authentication Filter

: 사용자 인증 필터

2. Logging and Auditing Filters

: 로깅 및 감시 필터

3. Image conversion Filters

: 이미지 변환 필터

4. Data compression Filters

: 데이터 압축 필터

5. Encrpytion Filters

: 암호화 필터

6. Tokenizing Filters

7. Filters that trigger resource access events

8. XSL/T filters

: XML 컨텐츠를 변형하는 XSLT 필터

9. MIME-type Chaine Filter

 

 

필터를 설정하는 FIlter Config, FilterChain, Filter 객체가 필요 

Filter 인터페이스는 init( ), doFilter( ), destroy( ) 가 있다.

init(FilterConfig config)

: 인스턴스 초기화 메서드 

doFilter(ServletRequest requ, ServletResponse res, FilterChain chain)

: 필터 로직을 담당하는 메서드

destroy( )

: 인스턴스 종료 전 실행하는 메서드

 

[Servlet] 서블릿 필터 (Filter) : 네이버 블로그 (naver.com)

 

[Servlet] 서블릿 필터 (Filter)

서블릿 필터(Servlet Filter)란? Client로 부터 Server로 요청이 들어오기 전에 서블릿을 거쳐서 필터...

blog.naver.com

 

 

public class testFilter implements Filter {

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

		System.out.println("필터 1번입니다.");
		request.setCharacterEncoding("UTF-8");
		System.out.println("1번 필터 do Filter 전");
		System.out.println(request.toString());
		
		chain.doFilter(request, response);
		
		System.out.println("1번 필터 do Filter 후");
		System.out.println(response.toString());
		System.out.println("필터 1번 끝");
	}
}

 

Servlet이 service( ) 메소드로 요청을 처리한 것처럼 필터는 doFilter( ) 메소드를 통해서 요청 처리.

모든 요청이 끝나면 destroy( ) 메소드가 호출되면서 필터는 비활성화

 

<filter>
	<filter-name>testFilter</filter-name>
	<display-name>testFilter</display-name>
	<filter-class>com.seol.testProject.filter.testFilter</filter-class>
</filter>
	
<filter>
	<filter-name>testFilter2</filter-name>
	<display-name>testFilter2</display-name>
	<filter-class>com.seol.testProject.filter.testFilter2</filter-class>
</filter>

	
<filter-mapping>
	<filter-name>testFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
	<filter-name>testFilter2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

 

여러 개의 filter 객체들을 순서를 가지고 서로 사슬처럼 연결되어 있어서 FilterChain이라고 한다.

필터는 요청받을 때 수행되고 chain.doFilter( ) 를 통해 다음으로 넘긴다. 

다음 부분이 모두 수행되면 응답 객체와 함께 다시 필터로 돌아온다.

따라서 chain.doFilter( ) 이전과 이후로 나뉜다.

 

doFilter 세 번째 파라미터로 FilterChain이 전달되는데

chain.doFilter 메서드를 통해 계속적으로 doFilter를 호출한다.

filterChain 정렬 순서는 web.xml에서 filter-mapping 정의 순서이다. 

 

 

<servlet>
	<servlet-name>dispatcher</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-mvc-demo-servlet.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<!-- 커스텀 서블릿 -->
<servlet>
	<servlet-name>testServlet</servlet-name>
	<display-name>testServlet</display-name>
	<servlet-class>com.seol.testProject.servlet.testServlet</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>dispatcher</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
	<servlet-name>testServlet</servlet-name>
	<url-pattern>/output</url-pattern>
</servlet-mapping>