[지금 무료] 스프링부트 개념정리(이론) | 최주호 - 인프런
최주호 | 스프링부트를 공부하며 헷갈리는 개념이 많았던 분 스프링부트에 대해 공부하고 싶었던 모든 분, 스프링부트의 핵심은확실한 개념으로부터! 스프링부트 너무 어려운데 어떻게 시작하
www.inflearn.com
http란 ?
http는 HyperText Transfer Protocold의 약어로 www상에서 html문서를 주고 받을 수 있는 통신규약이다. 브라우저에서 http를 통해 웹 서버로 html(웹 페이지)를 요청하면 서버는 요청에 응답하여 필요한 정보를 해당 브라우저에게 전달한다. http는 소켓 통신시 일어나는 부하를 줄이기 위해서 탄생했고 http는 소켓 기반이다. http는 통신시 stateless방식을 사용한다. stateless방식은 요청 후 응답이 완료될 시 연결이 종료되는 비연결형 방식이다. 웹서버는 클라이언트로부터 요청시 단순히 응답(정적(static) 자원)만 해준다
1) 스프링은 내장 톰켓을 가진다.
톰켓을 따로 설치할 필요 없이 바로 실행 가능하다.
톰켓이란 ?
웹서버인 아파치에 자바 혹은 JSP로 이루어진 요청하게 되면 아파치는 이해할 수 없다. 그래서 자바코드 요청시 응답할 수 없다. 그렇기 때문에 톰켓을 장착시켜 아파치에서 이해할 수 없는 파일에 대한 요청이 오면 제어권을 톰켓에 넘긴다. 톰켓은 .JSP 파일에 있는 모든 파일을 컴파일하고 컴파일이 끝나면 컴파일 된 파일을 .html에 덮어씌운다. 그 후 아파치에게 다시 돌려주어 응답을 한다. 웹에서 요청시 흔히 웹 브라우저로 요청을 하게 되는데 .JSP파일로 요청시 .JSP파일로 응답이 온다면 그냥 웹서버에 불과한다. 웹 브라우저에서는 html, JavaScript, CSS를 다루기 때문에 해당하는 파일을 제외한 파일로 응답이 온다면 웹에서는 해당 파일을 읽을 수 없어 내용이 깨지게 된다.
톰켓은 자바 형식의 코드를 컴파일하고 html문서로 만들어준 뒤 반환해주는 역할을 한다.
웹서버에 html, css, png 등 정적인 파일이 요청이 들어오면 톰켓이 아닌 아파치가 처리를 한다. 자바 파일 요청시 톰켓이 처리를 한다. 스프링은 정적인 파일을 요청할 수 없다. 요청방식은 2가지로 URL과 URI가 있다.
URL은 자원에 접근할때 사용하는 주소 요청 방식, URI는 식별자를 통해 접근하는 방식이다.
URL의 예: http://naver.com/a.png / URI의 예: http://naver.com/picture/a
스프링에서는 URL 접근방식을 막아뒀기 때문에 정적인 파일을 요청할 수 없다. URI는 특정한 파일 요청할 수 없다. 요청시 무조건 자바를 거쳐야 한다. 그렇기 때문에 무조건 적으로 아파치는 톰켓에게 제어권을 넘겨준다.
2) 서블릿 컨테이너(톰켓) 생명주기

클라이언트에서 Java관련된 자원을 요청시 무조건 서블릿 컨테이너가 요청이 된다. html, css 등 자바관련 자원이 아니라면 아파치가 담당하며 정적 웹 서버라고 한다. 서블릿 컨테이너의 생명주기는 아래와 같다.
1. 클라이언트에서 서버로 최초의 요청이 왔을때 서블릿 객체를 생성(new)한다.
1 - 1. 그후 해당 객체에 init() 메서드가 호출되어 초기화를 진행한다.
1 - 2. service() 메서드를 통해 Post, Get, Put, Delete 여부를 체크한다. service() 호출 직전에 스레드를 만들어 실행한다.
1 - 3. 요청에 따른 메서드가 호출된다. (Get이라면 Get(), Post라면 Post(), ... Put(), Delete())
1-4. 요청이 Get이라면 Get() 함수를 호출하여 DB에 연결하고 데이터를 받아 html에 담아서 응답을 한다.
request(자바 자원일 경우) → 서블릿 컨테이너 호출 → 서블릿 객체 생성(new) → init() → service() → Get(), Post(), ...
최초 요청 이후 다시 클라이언트에서 요청이 올때는 이전에 사용했던 서블릿 객체를 재사용한다. 객체 생성(new)와 초기화(init())는 건너뛰고 바로 새로운 스레드를 생성하여 Service()부터 진행된다.
자바에서 메모리의 영역은 크게 보면 static, heap, stack 이렇게 있는데, 먼저 클래스에 대해서 객체를 생성시 heap영역에 상주하게 된다. 해당 객체를 통해 동일 클래스 내부 메서드를 호출 시 해당 메서드 실행시 필요한 메모리는 stack영역에 상주한다. 이 stack 영역은 독립적이다. 요청하는 객체별로 모두 다 다른 독립적인 공간으로 주어진다. 메서드 호출에 대해서는 독립적인 stack영역이 주어진다.
위의 특징처럼 스프링에서도 최초 요청 이후 계속해서 요청이 들어온다면 새로운 스레드를 통해서 통신한다. 메모리 상주 공간이 다르기 때문에 서블릿 객체가 하나여도 스레드는 계속해서 만들어서 사용할 수 있다.
톰켓 기본설정으로 스레드의 개수를 제한할 수 있다.예를들어 스레드 개수 20개를 상한선으로 지정해둔다면 스레드 20번째까지 요청을 진행하고 21번째부터는 제한되기 때문에 대기하게 된다. 그리고 첫번째 스레드에 대해서 사용이 종료되고 응답이 완료된 시점에 21번째 요청에 대해서 첫번째 스레드를 재사용할 수 있게 된다. 이것을 Pooling 기법이라 한다.
최종적으로 정리하자면 클라이언트의 최초 요청시 request → 서블릿 객체 생성 → Get() → 스레드 생성 → 응답 완료 → 사용된 스레드는 제거하지 않고 남겨둔 뒤 재사용한다. 클라이언트가 동시 접속 시 상한선으로 제한을 둔 스레드 개수만큼만 사용할 수 있고 개수를 초과하는 요청은 대기후에 먼저들어온 요청에 대해 응답을 완료한 뒤 스레드를 재사용한다. 서블릿 객체의 개수는 1개이고 스레드의 개수는 하드웨어의 성능에 따라서 20개에서 100개등 다양하게 주어진다.
만약 과도하게 많은 요청이 들어온다면 방법은 2가지가 있다. 첫번째는 하드웨어의 성능을 업그레이드 하는 것이다. 이 방법을 Scale-up이라고 한다. 두번째는 분산처리하도록 만드는 방법이다. 예들들어 100명을 수용할 수 있는 하드웨어를 10개를 만들어 수평적으로 확장한다. 이 방법을 Scale-out이라고 한다.
3) web.xml
웹서버에 들어오면 최초에 진입을 하는게 web.xml이고 다양한 작업을 한다.
- ServletContext의 초기 파라미터
초기 파라미터는 암구호와 같은것이고 초기에 선언하면 어디서든 동작한다.
- Session의 유효시간 설정
세션은 암구호의 유효 기간이다. 설정할 수 있다.
- Servlet/JSP에 대한 정의
Servlet/JSP 대한 정의가 들어간다.
- Servlet/JSP 매핑
클라이언트에서 요청에 대해서 주소를 들고온다. web.xml에서는 주소를 가르켜준다. 요청한 자원, 위치, 식별자에 대해서 위치를 알려주고 이동을 도와준다.
- Mime Type 매핑
클라이언트에서 데이터를 가져올 수 있고 안가져올 수도 있다. 가져오지 않는 경우는 서버에서 원하는 요청을 가져가는 것이기 때문에 Get()방식(select)을 사용한다. 데이터를 가져온다면 먼저 해당 데이터를 Servlet/JSP 매핑을 통해 해당 위치에 옮긴 뒤 가져오는 데이터에 대해서 데이터의 형식을 확인 한 뒤 매핑하여 저장한다. 마임타입이 불일치한다면 에러가 발생한다.
- Welcome File list
아무런 목적이 없이 클라이언트가 접속한다면 최초로 접속할 지점을 정해준다. 개발자가 설정하기 나름이다.
- Error Pages 처리
잘못된 요청에 대한 처리이다. 에러페이지 (404, 505)가 해당된다.
- 리스너/필터 설정
리스너는 특정한 부분만 확인하며 강제성을 갖는다. 필터는 권한이다. 접속할 수 있는 권한에 대한 설정을 해야한다.
- 보안
웹 서버에 필요한 보안 작업도 설정한다.
4) FrontController 패턴
Servlet/JSP 매핑시(web.xml에 직접 매핑하거나 어노테이션(@)를 사용하는데)에 모든 클래스에 매핑을 적용시키기에는 코드가 복잡해지므로 FrontController 패턴을 사용한다.
최초 앞단의 request 요청을 받아 필요한 클래스에 바로 넘겨준다. web.xml에 모든 것을 정의하기 어렵기 때문이다.
이때 새로운 요청이 생기기 때문에 request와 response가 새롭게 new 될 수 있다. 그래서 RequestDispatcher가 필요하다.
요청(URI, 자바파일)이 들어올 시 특정 주소에 대해서 FrontController로 이동할 수 있도록 web.xml파일에 설정을 해둔다면 바로 자원에 접근할 수 없고, 톰켓으로 가게된다. 톰켓가면 request와 response 객체를 생성한다. request는 요청한 사람의 정보가 들어있다.(요청자가 어떤 데이터를 서버에 요청했는지, 어떤 데이터를 들고 접근을 했는지) request를 통해서 response 객체를 만든다. response는 응답해주는 정보이다. 이 작업을 톰켓이 자동으로 만들어준다. 그 뒤 특정 주소의 요청이라면 FrontController로 이동하여 다시 request 객체와 response객체를 만든다. 스프링에서는 자원에 직접 접근이 불가능하지만 내부에서의 접근은 가능하다. request 객체와 response객체를 다시 만들게 되면 원래 web.xml 접근시 만든 request객체와 response객체는 새로 만든 객체로 바뀌게 된다. 요청자의 정보가 사라지는 것을 방지하고자 기존의 request와 response객체를 유지하는 방법이 필요하다. 그 방법이 RequestDispatcher이다.
5) RequestDispatcher
필요한 클래스 요청이 도달했을 때 FrontController에 도착한 request와 response를 그대로 유지시켜준다.
쉽게 말하면 데이터를 들고 페이지를 이동할 수 있는 기법이 RequestDispatcher이다.
6) DispatchServlet
4, 5인 FrontController과 RequestDispatcher는 직접 구현할 필요가 없다. 스프링에서는 DispatchServlet가 있기 때문이다. DispatchServlet은 FrontController 패턴과 RequestDispatcher의 모음이기 때문이다.
DispatchServlet이 자동 생성되어 질 때 수많은 객체가 생성된다. 보통 필터들이다. 해당 필터들은 내가 직접 등록할 수 도 있고, 기본적으로 필요한 필터들은 자동 등록된다.
7) 스프링 컨테이너
DispatchServlet에 의해 생성되는 객체들의 관리
7 - 1) ApplicationContext
DispatchServlet는 위의 작업 외에도 컴포넌트 스캔 작업을 한다. DispatchServlet의 주 역할은 주소 분배인데 주소를 분배하려면 컴포넌트 스캔을 거쳐야 하기 때문이다.
요청에 대하여 처리를 할때에는 src(소스코드 폴더)에 있는 수 많은 자바 파일들이 메모리에 상주하고 있어야 한다. 모든 코드가 static으로 만들어져 있지 않다면 메모리 공간에 올라가기 위해선 new를 해야한다. static으로 만들어진 코드는 메인 메서드가 실행하기 전부터 메모리에 상주하고 있다. 반면에 자바파일은 객체이다. 특정시간에 메모리에 상주했다가 제거된다. 다수의 사용자가 요청하는 웹 페이지 특성상 모든 코드를 static로 만드는 것은 불가능 하기 때문에 DispatchServlet이 컴포넌트 스캔을 통해 자동적으로 위 작업을 src의 모든 파일을 대상으로 해준다. 버전별로 다르지만 스프링부트 이후는 모든 파일을 스캔한다. 자동적으로 특정 폴더 이하의 모든파일이 스캔 범위로 잡히게 된다. 모든 파일을 스캔 후 필요한 파일을 메모리에 올리게 된다. 필요한 파일인지 여부는 스프링에서 어노테이션 기법으로 정해뒀다. 메모리에 상주시킨 뒤 IoC로 관리한다. 메모리에 상주가 됐다면 주소를 분배할 수 있다.
모든 객체와 모든 스레드가 공통적으로 필요한 데이터베이스 관련된 것이나 이외의 공통적으로 필요한 부분들은 ContextLoaderListener이 메모리에 상주시킨다. 그 후 IoC 컨테이너에서 관리된다. ContextLoaderListener는 root-ApplicationContext 파일에 있고 커스터마이징까지 가능하다.
7 - 2) Bean Factory
필요한 객체를 Bean Factory에 등록하여 초기에 메모리에 상주시키지 않고 필요할때 getBean()메서드를 통해서 메모리에 상주시킬 수 있다. 위 방법 또한 IoC이다. 또 필요한 경우 DI하여 사용할 수 있다. ApplicationContext와 다른 점은 BeanFactory에 로드되는 객체들은 미리 로드되지 않고 필요할 때 호출하여 로드하기 때문에 lazy-로딩된다.
8) 요청 주소에 따른 적절한 컨트롤러 요청 (Handler Mapping)
Get요청이 http://localhost:8080/post/1 과 같은 형식으로 온다면 URI패턴으로 8080/ 이하는 식별자이다. 해당 주소 요청이 오면 적절한 컨트롤러의 함수를 찾아서 실행시킨다.'
9) 응답
html파일을 응답할지 데이터를 응답할지 결정해야 하는데 html파일을 응답할땐 ViewResolver가 관여한다. 데이터를 응답할땐 MessageConverter가 작동하여 MessageConverting시 json 데이터를 반환한다.
'Web > Spring Boot' 카테고리의 다른 글
| Spring Boot 라이브러리 (0) | 2024.04.02 |
|---|---|
| Spring Boot 파일 구조 (0) | 2024.04.01 |
| Spring Boot 프로젝트 생성 (0) | 2024.04.01 |
| Spring Boot JPA (0) | 2024.03.29 |
| Spring Boot 개념 (0) | 2024.03.28 |