카테고리 없음

메타코딩 - 스프링부트 개념정리 8~14강 - Springboot 동작원리

정현3 2022. 8. 30. 12:54

스프링부트 동작원리

1.  Http가 무엇일까?

socket이란? -> 운영체제가 가지고 있는것

Socket은 '운영체제'가 가지고 있는 것인데 예를들어 대상 A와 B가 메세지를 전달하고 싶을때 Socket을 이용하면 된다.
처음으로 Socket을 오픈한다(포트번호가 필요), B가 A에 A가 가진 IP주소와 Port번호를 넣어서 연결을 한다. 연결이 되는순간 메세지를 주고받을 수 있는 통신을 할 수 있다.
이때 C가 A와 통신을 하고 싶을때, A와 B는 연결되어 있기 때문에 C와 A는 통신을 할 수 없다.
"최초의 연결이 됬을 때 연결된 Port는 연결의 용도로만 쓰고 새로운 Socket을 만든 후 연결이 끊기고, Port는 랜덤으로 만들어진 다음 새로운 Socket에 B가 A와 연결이 되어 새로운 Socket으로 통신이 이루어진다"

socket통신 -> main스레드 -> 계속해서 사용자의 요청을 받고, 5001번 스레드는 B와 통신한다
C는 5000번에 접근할 수 있고, 새로운 스레드인 5002번이 생성된다. -> '소켓통신' -> timeslice -> "동시에 동작하는것처럼 보일 수 있다"
-> 장점은 연결이 끊어지지 않는다. 단점은 부하가 크다, 느려질 수 있다. -> 서버입장에서는 한번 연결된것을 계속 기억한다 -> Stateful방식

Http통신 -> 연결을 지속하지 않고 바로바로 연결을 끊어버리는 Stateless방식을 사용한다 -> 문서를 전달하는 통신 -> 연결됬던것을 기억하지 못한다 -> 부하가 적지만 매번 새로운 연결을 해야한다

A가 C에게 a.txt파일을 요청하면 C는 새로운 스레드를 만드는것이 아닌 바로 a.txt를 전송한다. 그리고 연결을 중단한다.
B도 만약 C에게 연결을 요청하면 응답 후 연결을 중단한다.

Http의 목적은 html확장자의 문서를 특정한 사람에게 전달해주는것이 목적이다.

 

2. 톰켓이란 무엇인가요?

HTTP 웹 서버는 '갑'이다. 필요한 정보를 가지고 있다. '을'의 IP주소를 알지 못한다. '을'의 주소를 알기 위해서는 Socket을 써야 한다.

Http는 '운영체제'가 가지고 있는 Socket기반이다.

"톰켓과 웹서버의 차이를 잘 알아야 하고 웹 서버에 대해 잘 알아야 한다"

'웹서버'는 '갑'이며 '을'이 필요한 데이터를 가지고 있다. Http통신은 '을'이 '갑'한테 request(요청)한다.

request하기 위해서는 IP주소를 알아야 하며 request시에 어떤 자원을 요청해야 하는지 명시를 해야한다. 이때 URL(자원을 요청하는 주소)를 통해 명시를 한다. 이때 요청시 응답해 주는 자원은 static자원 즉, '정적인 자원'이라 한다.

URL -> 자원을 요청하는 주소
URL에서 L은 Location이란 뜻이고 자원요청시 URL을 통해 해당자원을 요청할 수 있다. 응답시 '갑의입장'에서는 '을'
의 IP주소를 몰라도 된다

URI -> 식별자 접근

이 상황에서 알 수 있는 것은 '웹서버'는 '을'의 IP주소가 필요 없다는 것이다.

웹 서버 : 아파치 + 톰켓

아파치(웹 서버) -> 컴퓨터 내부의 파일 중 공유하고 싶은 폴더(파일)을 설정하면 해당 폴더는 요청, 응답이 가능한 폴더가 된다.
다른 사람이 해당 내부의 자원을 request할 시 웹 서버는 해당 자원을 response 해준다.
'아파치'는 .jsp, 자바코드 같은 파일은 응답해 주지 못한다. 이때 자바 코드를 인식해주기 위해 '톰켓'이라는것을 달아준다. 즉, 아파치가 응답해주지 못하는 자원을 처리해주는것이 톰켓이다.

아파치란? -> 요청한 파일을 응답해주는것

톰켓이란? -> "요청한 파일중에Java 코드를 컴파일하고 Html문서로 번역해주고 , 다시 아파치에게 돌려준다. 아파치는 해당 Html파일을 돌려준다."

 

3. 서블릿 객체의 생명주기란?

서블릿 컨테이너

'서블릿 컨테이너'란 클라이언트가 요청을 하면 '서블릿컨테이너(톰켓)'이 요청을 받고 '최초요청'이면 객체를 생성하고 아니면 이미 생성된 객체를 재사용한다.

정적인 파일(.html, .css, .png)을 요청을 하면 톰켓이 실행이 안되고 '아파치'가 동작을 한다.

자바 파일을 요청을 한다면 '톰켓'이 동작을 한다. 그러면 스프링에서도 톰켓이 일을 안할까? 맞다. but 스프링은 '정적인 파일'을 요청을 할 수 없다. 즉, 스프링에서는 특정한 파일 요청을 할 수 없다. 무조건 Java를 거쳐야 한다. -> 자원 요청시 '톰켓'에 요청을 반드시 해야한다.

Java자원이면 '서블릿컨테이너(톰켓)'실행
Java자원이 아니면 html.css -> '아파치' 실행

URL과 URI  비교예시
http://naver.com/a.png -> URL
http://naver.com/picture/a -> URI(식별자요청)

request가 왔을 때 '서블릿 컨테이너'가 객체를 생성하는 방식을 이해해야 한다. 
클라이언트가 request하게 되면 '서블릿 컨테이너'에서는 최초의 요청시 '쓰레드'를 생성한다.
이때 생성된 '쓰레드'가 '서블릿 객체'를 만든다. 왜 쓰레드가 만들어질까?
request가 한명이 아닌 수만명이 될 수도 있기 때문에 '동시처리'를 위해 '쓰레드'가 만들어진다.
쓰레드 생성 개수를 지정을 해놓고 '생성된 개수'보다 많ㅈ은 요청이 있을 시 그전 요청의 response까지 대기를 하고 response시 응답한 쓰레드가 재사용이 되며 이미 있는 '서블릿 객체'를 사용한다. -> 속도가 빠르다.

최종적으로 HttpServletRequest, HttpServletResponse 객체가 생성된다.

 

request요청을 하면 최초요청시에 '서블릿 객체'를 만든다. 필요한 메서드를 호출한다. '스레드'가 만들어진다
response시에 스레드1은 필요가 없어지나 재사용하기위해 남겨둔다.

다음 요청시에 '서블릿 객체'를 새로 만들지 않고 재사용해서 응답을 하게 된다

클라이언트들이 동시접근을 하면 '쓰레드'를 늘린다. 한도가 초과되면 나머지 인원은 '대기'한다.

'서블릿 객체'의 개수는 무조건 1개이다.

'쓰레드'의 개수를 늘리는 것 -> pooling 기술

 

4. Web.xml

- ServletContext의 초기 파라미터 설정 : 암구호

- Session의 유효시간 설정 : 인증을 통해 들어오는것 -> 초기화되면 다시 인증을 해야한다.

- Servlet/JSP에 대한 정의 : 

- Servlet/JSP 매핑 : 요청한 자원/식별자가 어디라는 것을 정확히 알려주고 도와주는것 : ServletMapping

- Mime Type 매핑 : 너가 들고올 데이터의 타입이 뭐야?

- Welcome File list : 처음 모이는 광장

- Error Pages 처리 : 이상한 광장으로 보내

- 리스너/필터 설정 : 새로운 문지기(대리인), A의 신분을 확인한다

- 보안 

-> 여기에서 Servlet/JSP 매핑시(web.xml에 직접 매핑 or @WebServlet 어노테이션 사용)에 모든 클래스에 매핑을 적용시키기에는 코드가 너무 복잡해지기 때문에 FrontController 패턴을 이용함

 

5. DispatcherServlet이 무엇인가요?

1. FrontController 패턴

최초 앞단에서 request요청을 받아서 필요한 클래스에 넘겨준다 -> 왜? web.xml에 다 정의하기가 너무 힘듬
.do(특정주소)가 들어오면 web.xml에 톰켓내부의 FrontController로 보내는 코드를 짜둔다.
'톰켓'으로 가면 최초의 request와 response 객체를 만듬
request는 '요청한 사람'의 정보를 들고있다. 요청한 사람이 어떤 데이터를 요청했는지 의 정보를 가지고 response를 만들어준다.

이때 '특정한 주소'가 들어오면 FrontContoller는 '특정 주소'를 낚아챈다. 그 후 '내부 자원' 접근을 위한 request를 진행한다.
이때 '새로운 요청'이 생기기 때문에 request와 response가 새롭게 new될 수 있다. 그래서 아래의 RequestDispatcher가 필요하다.

2. RequestDispatcher

필요한 클래스 요청이 도달했을 때 FrontController에 도착한 request와 response를 그대로 '유지'시켜준다. 
-> 데이터를 들고 페이지를 이동할 수 있게 해준다.

 

3. DispatcherServlet -> '주소 분배'

FrontController 패턴을 직접 짜거나 RequestDispatcher를 직접 구현할 필요가 없다. 왜냐하며 '스프링'에는 DispatcherServler이 있기 때문이다.
DispatcherServlet은 (FrontController 패턴 + RequestDispatcher)이다.

DispatcherServlet이 '자동생성'되어 질 때 수 많은 객체가 생성(IoC)된다. 보통 '필터'들이다.
해당 필터들은 내가 '직접 등록'할 수 도 있고, 기본적으로 필요한 필터들은 '자동 등록'되어진다.

 

6. 스프링 컨테이너

-> '아파치'는 머릿속에서 지우자. 스프링은 '정적인 파일'을 쓸일이 없다. 모두 Java파일인 Servlet을 요청을 한다.

DispatcherServlet에 의해 생성되어지는 수 많은 객체들은 어디에서 관리될까?

1.  ApplicationContext

수 많은 객체들이 ApplicationContext에 등록됨. 이것을 IoC(제어의 역전)라고 함.
개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가리키는 '레퍼런스 변수'를 관리하기 어렵기 때문에 '스프링'이 직접 해당 객체를 관리한다. 이때 우리는 주소를 몰라도 된다. -> "필요할 때 DI(의존성 주입)하면 되기 때문에"
-> 필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져올 수 있다
-> ApplicationContext는 '싱글톤'으로 관리되기 때문에 어디에서 접근하든 '동일한 객체'라는것을 보장해준다.

ApplicationContext의 종류에는 두가지가 있는데 (root-applicationContext와 serlvet-applicationContext)이다.

servlet-applicationContext는 ViewResolver, Interceptor, MultipartResolver 객체를 생성하고 웹과 관련된 어노테이션 Controller, RestController를 스캔한다.
-> 해당 파일은 DispatcherServlet에 의해 실행된다.

root-applicationContext는 해당 어노테이션을 제외한 어노테이 Service, Repository 등을 스캔하고 DB관련 객체를 생성한다.
-> 스캔 : 메모리에 로딩한다

해당 파일은 ContextLoaderListener에 의해 실행된다. ContextLoaderListener를 실행해주는 것은 web.xml이기 때문에 root-applicationContext는 servlet-applicationContext보다 먼저 로드된다.

당연히 servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만 그 반대는 불가능하다.
'생성 시점'이 다르기 때문이다.

request하면 '톰캣'이 반응을 하며 web.xml에서 '스프링 내부'로 들어가기 위해 두가지 일을 한다.

첫번째로 DispatcherServlet이 동작을 한다. src 소스폴더 내부의 모든 파일을 '컴포넌트 스캔'을 한다. 즉, 어노테이션이 붙은 자바파일 모든것을 DispatcherSerlvet이 '컴포넌트 스캔'을 하고 주소를 분배한다.

두번째는 ContextLoaderListener이다. 

위의 과정을 진행하기 전 ContextLoaderListener가 root-ApplicationContext 파일을 읽어와 공통적으로 사용하는 것들을 미리 메모리에 세팅한다.

2. Bean Factory

필요한 객체를 Bean Factory에 등록할 수도 있다. 여기에 등록하면 초기에 메모리에 로드되지 않고 필요할 때 getBean()이라는 메서드를 통하여 호출하여 메모리에 로드할 수 있다. 이것또한 IoC이다. 그리고 필요할 때 DI하여 사용할 수 있다.

ApplicationContext와 다른점은 Bean Factory에 로드되는 객체들은 미리 로드되지 않고 필요할 때 호출하여 로드하기 때문에 lazy-loading이 된다.

 

7. 요청 주소에 따른 적절한 컨트롤로 요청 (Handler Mapping)

GET 요청 -> http://localhost:8080/post/1
해당 주소 요청이 오면 적절한 컨트롤러의 함수를 찾아서 실행한다.

8. 응답

html파일을 응답할지 Data를 응답할 지 결정해야 하는데, html파일을 응답하게 되면 ViewResolver가 관여하게 된다.
하지만 Data를 응답하게 되면 MessageConverter가 작동하게 되는데 메세지를 컨버팅할 때 기본 전략을 JSON이다.